diff --git a/flow-Agent/AutoTuner-integration/ORFS-with-AutoTuner/analyst_agent_workbench.py b/flow-Agent/AutoTuner-integration/ORFS-with-AutoTuner/analyst_agent_workbench.py index 939872c..785e1d5 100644 --- a/flow-Agent/AutoTuner-integration/ORFS-with-AutoTuner/analyst_agent_workbench.py +++ b/flow-Agent/AutoTuner-integration/ORFS-with-AutoTuner/analyst_agent_workbench.py @@ -9,12 +9,47 @@ import anthropic # type: ignore import time # For retry delay import random # For placeholder BayesOpt, can be removed if BayesOpt is robust +from pathlib import Path # For Bayesian Optimization from skopt import Optimizer from skopt.space import Real, Integer, Categorical from skopt.utils import use_named_args # For easier handling of parameters +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from rag.util import answerWithRAG, modelUtility +from sentence_transformers import SentenceTransformer +import torch + +## ========== New addition: Three QA data paths========== +base_dir = Path(__file__).parent + +# Construct a relative path +qa_paths = [ + base_dir.parent.parent / "EDA-Corpus-main" / "Augmented_Data" / "Question-Answer" / "Flow" / "Flow.csv", + base_dir.parent.parent / "EDA-Corpus-main" / "Augmented_Data" / "Question-Answer" / "General" / "General.csv", + base_dir.parent.parent / "EDA-Corpus-main" / "Augmented_Data" / "Question-Answer" / "Tools" / "Tools.csv", +] +merged_csv_path = "RAGData/RAGFLOWGUIDE.csv" # Unify the file path of the vector library +os.makedirs("RAGData", exist_ok=True) + +def merge_qa_files(file_list, output_path): + dfs = [] + for path in file_list: + if os.path.exists(path): + df = pd.read_csv(path) + # Clean up duplicates and blank lines + df = df.drop_duplicates().dropna(how="any") + dfs.append(df) + print(f"[RAG] Loaded file: {path}, containing {len(df)} records.") + else: + print(f"[Warning] The file does not exist: {path}") + if dfs: + merged = pd.concat(dfs, ignore_index=True) + merged.to_csv(output_path, index=False) + print(f"[RAG] The QA files have been merged into {output_path}, totaling {len(merged)} pieces of data.") + else: + raise FileNotFoundError("[Error] No valid QA files were found.") # --- Global State for Tools --- TOOL_STATE = { "current_df": pd.DataFrame(), @@ -190,6 +225,17 @@ def get_sample_rows(n_rows=3, query_string=None): return header + ":\n" + df_to_sample.sample(actual_n_rows).to_string() except Exception as e: return "Error in get_sample_rows: " + str(e) + "\n" + traceback.format_exc() +def get_rag_context(query, topk=6): + """ + Answer questions using the RAG database. + query: Query strings of users or LLMS + topk: Search for the top k relevant documents + """ + try: + return answerWithRAG(query, embeddings, embeddingModel, docs, docsDict, topk=topk) + except Exception as e: + return f"Error in RAG retrieval: {str(e)}" + def suggest_bayesian_optimization_configs(target_metric_to_minimize, n_suggestions=5, training_data_query=None, validation_data_query=None): log_to_file_and_console("[BAYESOPT] Called suggest_bayesian_optimization_configs.") log_to_file_and_console("[BAYESOPT] Target metric: " + str(target_metric_to_minimize)) @@ -383,6 +429,7 @@ def suggest_bayesian_optimization_configs(target_metric_to_minimize, n_suggestio "get_sample_rows": get_sample_rows, "reset_data_to_all_valid_runs": reset_data_to_all_valid_runs, "suggest_bayesian_optimization_configs": suggest_bayesian_optimization_configs, + "get_rag_context": get_rag_context, "suggest_new_tool": lambda suggested_tool_name, suggested_tool_description: log_to_file_and_console("[LLM TOOL SUGGESTION]\nName: " + str(suggested_tool_name) + "\nDescription: " + str(suggested_tool_description)) or "New tool suggestion noted: " + str(suggested_tool_name) } @@ -506,7 +553,20 @@ def suggest_bayesian_optimization_configs(target_metric_to_minimize, n_suggestio }, "required": ["target_metric_to_minimize"] } + }, + { + "name": "get_rag_context", + "description": "Retrieve the RAG database of OpenROAD-Agent and return relevant API documentation or code snippets for auxiliary analysis.", + "input_schema": { + "type": "object", + "properties": { + "query": {"type": "string", "description": "The question to be queried"}, + "topk": {"type": "integer", "default": 6, "description": "The number of relevant documents returned"} + }, + "required": ["query"] + } } + ] def run_agent_workbench(main_df=None, circuit=None, pdk=None, @@ -551,6 +611,20 @@ def run_agent_workbench(main_df=None, circuit=None, pdk=None, except Exception as e: print("Error initializing Anthropic client: " + str(e)) return + + try: + embeddings_np, docs, docsDict = load_embeddings_and_docs() + embeddings = torch.tensor(embeddings_np) + embeddingModel = SentenceTransformer("mxbai-embed-large-v1") + print("[RAG] The vector database was successfully loaded.") + except FileNotFoundError: + print("[RAG] The vector library does not exist and is under construction...") + merge_qa_files(qa_paths, merged_csv_path) + build_and_save_embeddings(merged_csv_path) + embeddings_np, docs, docsDict = load_embeddings_and_docs() + embeddings = torch.tensor(embeddings_np) + embeddingModel = SentenceTransformer("mxbai-embed-large-v1") + print("[RAG] The vector library has been built and loaded.") session_uuid = uuid.uuid4() context_file_name = log_dir + "/" + args.circuit + "_" + args.pdk + "_" + args.optimization_goal + "_context_" + str(session_uuid) + ".txt" diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.csv new file mode 100644 index 0000000..c0d0783 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.csv @@ -0,0 +1,2519 @@ +code,prompt +"# Invert the rotation and the location of instances with the library cell type 'NAND2_X1'. + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the name of the library cell type is 'NAND2_X1' + if inst.getMaster().getName() == 'NAND2_X1': + # Invert the rotation and the location of the instance + transform = inst.getTransform() + transform.invert() + inst.setTransform(transform)",Invert the rotation and the location of instances with the library cell type 'NAND2_X1' +"# Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Horizontally flip the rotation of the instance + orient = inst.getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Horizontally flip the rotation of the instances whose library cell types are 'NAND2_X1' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'NAND2_X1' + if inst.getMaster().getName() == 'NAND2_X1': + # Horizontally flip the rotation of the instance + orient = inst.getTransform().getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the rotation of the instances whose library cell types are 'NAND2_X1' +"# Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Horizontally flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipX(orient) + transform.setOrient(orient) + inst.setTransform(transform)",Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + transform.setOrient(orient) + inst.setTransform(transform) ",Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'NAND2_X1' + if inst.getMaster().getName() == 'NAND2_X1': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the rotation of the instances whose library cell types are 'NAND2_X1' +"# Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Vertically flip the rotation of the instance + orient = inst.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Set the rotation of the instance '_411_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'MX' +inst.setOrient('MX')",set the rotation of the instance '_411_' to 'MX' +"# Set the rotation of the instance '_411_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",set the rotation of the instance '_411_' to 'MX' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst('input1') +# Get the orientation of the instance +orient = inst.getOrient() +# Check if the orientation is ""MX"" +if orient == 'MX': + # Set the orientation of the instance to ""R0"" + inst.setOrient('R0') +elif orient == 'R0': + # Set the orientation of the instance to ""MX"" + inst.setOrient('MX')",Change the rotation of an instance 'input0'. If the rotation is 'MX' change it to 'R0' and vise versa +"# Set the rotation of the instance '_411_' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'R0' +inst.setOrient('R0')",set the rotation of the instance '_411_' to 'R0' +"# Set the rotation of the instance '_411_' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'R0' +transform = inst.getTransform() +transform.setOrient('R0') +inst.setTransform(transform)",set the rotation of the instance '_411_' to 'R0' +"# Set the rotation of the instance 'reg[0]_123' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('reg[0]_123') + +# Set the rotation of the instance to 'R0' +inst.setOrient('R0')",set the rotation of the instance 'reg[0]_123' to 'R0' +"# Set the rotation of the instance 'reg[0]_123' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('reg[0]_123') + +# Set the rotation of the instance to 'R0' +transform = inst.getTransform() +transform.setOrient('R0') +inst.setTransform(transform)",set the rotation of the instance 'reg[0]_123' to 'R0' +"# Set the rotation of the instance '118_i[0]' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Set the rotation of the instance to 'R90' +inst.setOrient('R90')",set the rotation of the instance '118_i[0]' to 'R90' +"# Set the rotation of the instance '118_i[0]' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Set the rotation of the instance to 'R90' +transform = inst.getTransform() +transform.setOrient('R90') +inst.setTransform(transform)",set the rotation of the instance '118_i[0]' to 'R90' +"# Set the rotation of the instance 'super40' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Set the rotation of the instance to 'R90' +inst.setOrient('R90')",set the rotation of the instance 'super40' to 'R90' +"# Set the rotation of the instance 'super40' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Set the rotation of the instance to 'R90' +transform = inst.getTransform() +transform.setOrient('R90') +inst.setTransform(transform)",set the rotation of the instance 'super40' to 'R90' +"# Set the rotation of the instance '118_i[0]' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Set the rotation of the instance to 'R180' +inst.setOrient('R180')",set the rotation of the instance '118_i[0]' to 'R180' +"# Set the rotation of the instance '118_i[0]' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Set the rotation of the instance to 'R180' +transform = inst.getTransform() +transform.setOrient('R180') +inst.setTransform(transform)",set the rotation of the instance '118_i[0]' to 'R180' +"# Set the rotation of the instance 'super40' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Set the rotation of the instance to 'R180' +inst.setOrient('R180')",set the rotation of the instance 'super40' to 'R180' +"# Set the rotation of the instance 'super40' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Set the rotation of the instance to 'R180' +transform = inst.getTransform() +transform.setOrient('R180') +inst.setTransform(transform)",set the rotation of the instance 'super40' to 'R180' +"# Set the rotation of the instance 'icache_1/_21661_' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'R270' +inst.setOrient('R270')",set the rotation of the instance 'icache_1/_21661_' to 'R270' +"# Set the rotation of the instance 'icache_1/_21661_' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'R270' +transform = inst.getTransform() +transform.setOrient('R270') +inst.setTransform(transform)",set the rotation of the instance 'icache_1/_21661_' to 'R270' +"# Set the rotation of the instance 'input31' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'R270' +inst.setOrient('R270')",set the rotation of the instance 'input31' to 'R270' +"# Set the rotation of the instance 'input31' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'R270' +transform = inst.getTransform() +transform.setOrient('R270') +inst.setTransform(transform)",set the rotation of the instance 'input31' to 'R270' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MY' +inst.setOrient('MY')",set the rotation of the instance 'icache_1/_21661_' to 'MY' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MY' +transform = inst.getTransform() +transform.setOrient('MY') +inst.setTransform(transform)",set the rotation of the instance 'icache_1/_21661_' to 'MY' +"# Set the rotation of the instance 'input31' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MY' +inst.setOrient('MY')",set the rotation of the instance 'input31' to 'MY' +"# Set the rotation of the instance 'input31' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MY' +transform = inst.getTransform() +transform.setOrient('MY') +inst.setTransform(transform)",set the rotation of the instance 'input31' to 'MY' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MYR90' +inst.setOrient('MYR90')",set the rotation of the instance 'icache_1/_21661_' to 'MYR90' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MYR90' +transform = inst.getTransform() +transform.setOrient('MYR90') +inst.setTransform(transform)",set the rotation of the instance 'icache_1/_21661_' to 'MYR90' +"# Set the rotation of the instance 'input31' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MYR90' +inst.setOrient('MYR90')",set the rotation of the instance 'input31' to 'MYR90' +"# Set the rotation of the instance 'input31' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MYR90' +transform = inst.getTransform() +transform.setOrient('MYR90') +inst.setTransform(transform)",set the rotation of the instance 'input31' to 'MYR90' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MX' +inst.setOrient('MX')",set the rotation of the instance 'icache_1/_21661_' to 'MX' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",set the rotation of the instance 'icache_1/_21661_' to 'MX' +"# Set the rotation of the instance 'input31' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MX' +inst.setOrient('MX')",set the rotation of the instance 'input31' to 'MX' +"# Set the rotation of the instance 'input31' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",set the rotation of the instance 'input31' to 'MX' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MXR90' +inst.setOrient('MXR90')",set the rotation of the instance 'icache_1/_21661_' to 'MXR90' +"# Set the rotation of the instance 'icache_1/_21661_' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Set the rotation of the instance to 'MXR90' +transform = inst.getTransform() +transform.setOrient('MXR90') +inst.setTransform(transform)",set the rotation of the instance 'icache_1/_21661_' to 'MXR90' +"# Set the rotation of the instance 'input31' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MXR90' +inst.setOrient('MXR90')",set the rotation of the instance 'input31' to 'MXR90' +"# Set the rotation of the instance 'input31' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Set the rotation of the instance to 'MXR90' +transform = inst.getTransform() +transform.setOrient('MXR90') +inst.setTransform(transform)",set the rotation of the instance 'input31' to 'MXR90' +"# Change the rotation of the instance 'wire2741' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('wire2741') + +# Change the rotation of the instance to 'R0' +inst.setOrient('R0')",change the rotation of the instance 'wire2741' to 'R0' +"# Change the rotation of the instance 'wire2741' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('wire2741') + +# Change the rotation of the instance to 'R0' +transform = inst.getTransform() +transform.setOrient('R0') +inst.setTransform(transform)",change the rotation of the instance 'wire2741' to 'R0' +"# Change the rotation of the instance 'wire2741' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('wire2741') + +# Change the rotation of the instance to 'R0' +inst.setOrient('R0')",Change the rotation of the instance 'wire2741' to 'R0' +"# Change the rotation of the instance 'wire2741' to 'R0' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('wire2741') + +# Change the rotation of the instance to 'R0' +transform = inst.getTransform() +transform.setOrient('R0') +inst.setTransform(transform)",Change the rotation of the instance 'wire2741' to 'R0' +"# Change the rotation of the instance 'max_cap2482' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('max_cap2482') + +# Change the rotation of the instance to 'R90' +inst.setOrient('R90')",Change the rotation of the instance 'max_cap2482' to 'R90' +"# Change the rotation of the instance 'max_cap2482' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('max_cap2482') + +# Change the rotation of the instance to 'R90' +transform = inst.getTransform() +transform.setOrient('R90') +inst.setTransform(transform)",Change the rotation of the instance 'max_cap2482' to 'R90' +"# Change the rotation of the instance 'super40' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Change the rotation of the instance to 'R90' +inst.setOrient('R90')",Change the rotation of the instance 'super40' to 'R90' +"# Change the rotation of the instance 'super40' to 'R90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Change the rotation of the instance to 'R90' +transform = inst.getTransform() +transform.setOrient('R90') +inst.setTransform(transform)",Change the rotation of the instance 'super40' to 'R90' +"# Change the rotation of the instance '118_i[0]' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Change the rotation of the instance to 'R180' +inst.setOrient('R180')",Change the rotation of the instance '118_i[0]' to 'R180' +"# Change the rotation of the instance '118_i[0]' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('118_i[0]') + +# Change the rotation of the instance to 'R180' +transform = inst.getTransform() +transform.setOrient('R180') +inst.setTransform(transform)",Change the rotation of the instance '118_i[0]' to 'R180' +"# Change the rotation of the instance 'super40' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Change the rotation of the instance to 'R180' +inst.setOrient('R180')",Change the rotation of the instance 'super40' to 'R180' +"# Change the rotation of the instance 'super40' to 'R180' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('super40') + +# Change the rotation of the instance to 'R180' +transform = inst.getTransform() +transform.setOrient('R180') +inst.setTransform(transform)",Change the rotation of the instance 'super40' to 'R180' +"# Change the rotation of the instance 'icache_1/_21661_' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'R270' +inst.setOrient('R270')",Change the rotation of the instance 'icache_1/_21661_' to 'R270' +"# Change the rotation of the instance 'icache_1/_21661_' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'R270' +transform = inst.getTransform() +transform.setOrient('R270') +inst.setTransform(transform)",Change the rotation of the instance 'icache_1/_21661_' to 'R270' +"# Change the rotation of the instance 'input31' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'R270' +inst.setOrient('R270')",Change the rotation of the instance 'input31' to 'R270' +"# Change the rotation of the instance 'input31' to 'R270' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'R270' +transform = inst.getTransform() +transform.setOrient('R270') +inst.setTransform(transform)",Change the rotation of the instance 'input31' to 'R270' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MY' +inst.setOrient('MY')",Change the rotation of the instance 'icache_1/_21661_' to 'MY' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MY' +transform = inst.getTransform() +transform.setOrient('MY') +inst.setTransform(transform)",Change the rotation of the instance 'icache_1/_21661_' to 'MY' +"# Change the rotation of the instance 'input31' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MY' +inst.setOrient('MY')",Change the rotation of the instance 'input31' to 'MY' +"# Change the rotation of the instance 'input31' to 'MY' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MY' +transform = inst.getTransform() +transform.setOrient('MY') +inst.setTransform(transform)",Change the rotation of the instance 'input31' to 'MY' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MYR90' +inst.setOrient('MYR90')",Change the rotation of the instance 'icache_1/_21661_' to 'MYR90' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MYR90' +transform = inst.getTransform() +transform.setOrient('MYR90') +inst.setTransform(transform)",Change the rotation of the instance 'icache_1/_21661_' to 'MYR90' +"# Change the rotation of the instance 'input31' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MYR90' +inst.setOrient('MYR90')",Change the rotation of the instance 'input31' to 'MYR90' +"# Change the rotation of the instance 'input31' to 'MYR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MYR90' +transform = inst.getTransform() +transform.setOrient('MYR90') +inst.setTransform(transform)",Change the rotation of the instance 'input31' to 'MYR90' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MX' +inst.setOrient('MX')",Change the rotation of the instance 'icache_1/_21661_' to 'MX' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",Change the rotation of the instance 'icache_1/_21661_' to 'MX' +"# Change the rotation of the instance 'input31' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MX' +inst.setOrient('MX')",Change the rotation of the instance 'input31' to 'MX' +"# Change the rotation of the instance 'input31' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",Change the rotation of the instance 'input31' to 'MX' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MXR90' +inst.setOrient('MXR90')",Change the rotation of the instance 'icache_1/_21661_' to 'MXR90' +"# Change the rotation of the instance 'icache_1/_21661_' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('icache_1/_21661_') + +# Change the rotation of the instance to 'MXR90' +transform = inst.getTransform() +transform.setOrient('MXR90') +inst.setTransform(transform)",Change the rotation of the instance 'icache_1/_21661_' to 'MXR90' +"# Change the rotation of the instance 'input31' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MXR90' +inst.setOrient('MXR90')",Change the rotation of the instance 'input31' to 'MXR90' +"# Change the rotation of the instance 'input31' to 'MXR90' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input31') + +# Change the rotation of the instance to 'MXR90' +transform = inst.getTransform() +transform.setOrient('MXR90') +inst.setTransform(transform)",Change the rotation of the instance 'input31' to 'MXR90' +"# Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the instance + orient = inst.getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the instance + orient = inst.getTransform().getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipX(orient) + transform.setOrient(orient) + inst.setTransform(transform)",Horizontally flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + transform.setOrient(orient) + inst.setTransform(transform) +",Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the instance + orient = inst.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Horizontally flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the cell + orient = inst.getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the cells whose library cell types are 'OR2_X3' +"# Horizontally flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the cell + orient = inst.getTransform().getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the cells whose library cell types are 'OR2_X3' +"# Horizontally flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Horizontally flip the rotation of the cells\ + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipX(orient) + transform.setOrient(orient) + inst.setTransform(transform)",Horizontally flip the cells whose library cell types are 'OR2_X3' +"# Vertically flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the cell + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + transform.setOrient(orient) + inst.setTransform(transform) +",Vertically flip the rotation of the instances whose library cell types are 'OR2_X3' +"# Vertically flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the cell + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the cells whose library cell types are 'OR2_X3' +"# Vertically flip the cells whose library cell types are 'OR2_X3' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the library cell type is 'OR2_X3' + if inst.getMaster().getName() == 'OR2_X3': + # Vertically flip the rotation of the cell + orient = inst.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the cells whose library cell types are 'OR2_X3' +"# Invert the rotation and the location of instances with the library cell type 'AND2_X1'. + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the name of the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Invert the rotation and the location of the instance + transform = inst.getTransform() + transform.invert() + inst.setTransform(transform)",Invert the rotation and the location of instances with the library cell type 'AND2_X1' +"# Invert the rotation and the location of instances with the library cell type 'OR2_X2'. + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the name of the library cell type is 'OR2_X2' + if inst.getMaster().getName() == 'OR2_X2': + # Invert the rotation and the location of the instance + transform = inst.getTransform() + transform.invert() + inst.setTransform(transform)",Invert the rotation and the location of instances with the library cell type 'OR2_X2' +"# Invert the rotation and the location of cells with the library cell type 'NOR_X3' + +# Get the design block +block = design.getBlock() + +# Get all cells in the block +insts = block.getInsts() + +# Iterate through all cells in the block +for inst in insts: + # Check if the name of the library cell type is 'NOR_X3' + if inst.getMaster().getName() == 'NOR_X3': + # Invert the rotation and the location of the cell + transform = inst.getTransform() + transform.invert() + inst.setTransform(transform)",Invert the rotation and the location of cells with the library cell type 'NOR_X3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input2' as mentioned in the prompt +inst = block.findInst('input2') +# Set the orientation of the instance as ""MX"" +inst.setOrient('MX')",Adjust the orientation of the instance 'input2' to 'MX'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input2' as mentioned in the prompt +inst = block.findInst('input2') +# Set the rotation of the instance as ""MX"" +inst.setOrient('MX')",Adjust the rotation of the instance 'input2' to 'MX'. +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""split30"" +inst = block.findInst(""split30"") +# Define the new library cell name +new_mast_name = 'BUF_X4' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Upsize the instance split30 to BUF_X4 +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""split30"" +inst = block.findInst(""split30"") +# Define the new library cell name +new_mast_name = 'BUF_X1' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False",Downsize the instance split30 to BUF_X1 +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""_32937_"" +inst = block.findInst(""_32937_"") +# Define the new library cell name +new_mast_name = 'AND2_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False",Scale up the size of the instance _32937_ to AND2_X3 +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""rebuffer_30"" +inst = block.findInst(""rebuffer_30"") +# Define the new library cell name +new_mast_name = 'BUF_X4' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use BUF_X4 to replace the instance ""rebuffer_30""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""rebuffer_30"" +inst = block.findInst(""rebuffer_30"") +# Define the name of the replacing library cell +new_mast_name = 'BUF_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use BUF_X3 to replace the cell ""rebuffer_30""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'CLKBUF_X2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use CLKBUF_X2 to replace the cell ""clkbuf_1_1__f_clk""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'clk_bufferx2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use clk_bufferx2 to replace the cell ""clkbuf_1_1__f_clk""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'clkbufferx2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use clkbufferx2 to replace the cell ""clkbuf_1_1__f_clk""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'CLK_BUF_X4' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Use CLK_BUF_X4 to replace the cell ""clkbuf_1_1__f_clk""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""split30"" +inst = block.findInst(""split30"") +# Define the new library cell name +new_mast_name = 'BUF_X1' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False",Downsize the cell split30 using BUF_X1 +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""split33"" +inst = block.findInst(""split33"") +# Define the new library cell name +new_mast_name = 'BUF_X2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False",Downsize the cell split33 using BUF_X2 +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""input104"" +inst = block.findInst(""input104"") +# Define the new library cell name +new_mast_name = 'BUF_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Upsize the instance input104 to BUF_X3 +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""output_104"" +inst = block.findInst(""output_104"") +# Define the new library cell name +new_mast_name = 'OR2_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Upsize the instance output_104 to OR2_X3 +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""output_104"" +inst = block.findInst(""output_104"") +# Define the new library cell name +new_mast_name = 'NOR2_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Upsize the instance output_104 to NOR2_X3 +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""output_104"" +inst = block.findInst(""output_104"") +# Define the new library cell name +new_mast_name = 'NOR_2X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Upsize the instance output_104 to NOR_2X3 +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'and_gate2_x9' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Replace the instance called ""msg_and_gate_118"" with the llibrary cell ""and_gate2_x9""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""input_118"" +inst = block.findInst(""input_118"") +# Define the name of the replacing library cell +new_mast_name = 'NANDx3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Replace the instance called ""input_118"" with the llibrary cell ""NANDx3""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""input_118"" +inst = block.findInst(""input_118"") +# Define the name of the replacing library cell +new_mast_name = 'NANDx3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast)","Replace the instance called ""input_118"" with the llibrary cell ""NANDx3""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'and_gate2_x9' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast)","Replace the instance called ""msg_and_gate_118"" with the llibrary cell ""and_gate2_x9""" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'and_gate2_x9' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")","Replace the instance called ""msg_and_gate_118"" with the llibrary cell ""and_gate2_x9""" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""input104"" +inst = block.findInst(""input104"") +# Define the new library cell name +new_mast_name = 'BUF_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")",Upsize the instance input104 to BUF_X3. +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""_32937_"" +inst = block.findInst(""_32937_"") +# Define the new library cell name +new_mast_name = 'AND2_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")",Scale up the size of the instance _32937_ to AND2_X3. +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find the instance named ""_32937_"" +inst = block.findInst(""_32937_"") +# Define the new library cell name +new_mast_name = 'AND2_X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")","How can I scale up the size of the instance ""_32937_"" using AND2_X3?" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'and_gate2_x9' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")","How can I replace the instance ""msg_and_gate_118"" with the llibrary cell ""and_gate2_x9""?" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'and_gate2_x9' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")","Can you give me the script to replace the instance ""msg_and_gate_118"" with the llibrary cell ""and_gate2_x9""?" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""msg_and_gate_118"" +inst = block.findInst(""msg_and_gate_118"") +# Define the name of the replacing library cell +new_mast_name = 'AND2_X6' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) +else: + print(""The library cell does not exist"")","Can you give me the script to replace the instance ""msg_and_gate_118"" with the master ""AND2_X6""?" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'clkbufferx2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","How can I use clkbufferx2 to replace the cell ""clkbuf_1_1__f_clk""?" +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""clkbuf_1_1__f_clk"" +inst = block.findInst(""clkbuf_1_1__f_clk"") +# Define the name of the replacing library cell +new_mast_name = 'clkbufferx2' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","Show me how I can use clkbufferx2 to replace the cell ""clkbuf_1_1__f_clk""." +"# Get the design block +block = ord.get_db_block() +# Get the openroad database +db = ord.get_db() +# Find cell ""_input_221_"" +inst = block.findInst(""_input_221_"") +# Define the name of the replacing library cell +new_mast_name = 'XOR3x5 ' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the required library cell + inst.swapMaster(new_mast) + return True +else: + return False","How can I use XOR3x5 to replace the cell ""_input_221_""?" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""output_104"" +inst = block.findInst(""output_104"") +# Define the new library cell name +new_mast_name = 'NOR_2X3' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Show me how I can upsize the instance output_104 to NOR_2X3. +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Find the instance named ""output_118 "" +inst = block.findInst(""output_118 "") +# Define the new library cell name +new_mast_name = 'NOR_2X6' +# Check if the required library cell exists in the database +if db.findMaster(new_mast_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_mast_name) + # Swap the instance's library cell with the new libarary cell + inst.swapMaster(new_mast) + return True +else: + return False",Show me how I can upsize the instance output_118 using NOR_2X6. +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'BUF_X2' +mast = db.findMaster('BUF_X2') +# Create a new instance named 'new_inst_1' using the 'BUF_X2' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","Add a new instance 'new_inst_1' using buffer cell BUF_X2 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1'" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'bufferx3' +mast = db.findMaster('bufferx3') +# Create a new instance named 'new_inst_1' using the 'bufferx3' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","Add a new instance 'new_inst_1' using buffer cell bufferx3 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1'" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'bufferx3' +mast = db.findMaster('bufferx3') +# Create a new instance named 'new_inst_1' using the 'bufferx3' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","Add a new instance 'new_inst_1' using library cell bufferx3 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1'" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'bufferx3' +mast = db.findMaster('bufferx3') +# Create a new instance named 'new_inst_1' using the 'bufferx3' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","How can I add a new instance 'new_inst_1' using library cell bufferx3 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1'?" +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'bufferx3' +mast = db.findMaster('bufferx3') +# Create a new instance named 'new_inst_1' using the 'bufferx3' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","Add a new instance 'new_inst_1' using library cell bufferx3 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1' " +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Find the net with name ""req_msg[17]"" +net = block.findNet('req_msg[17]') +# Connect the port and the net +port.connect(net)",Connect the port named 'req_val' and net named 'req_msg[17]' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Disconnect the port +port.disconnect()",Disconnect the port named 'req_val' from the nets it is connected to +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VDD_net = design.getBlock().findNet(""VDD"") +# Rip up the VDD grids +pdn_obj.ripUp(VDD_net)",Rip up the VDD grids +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VSS_net = design.getBlock().findNet(""VSS"") +# Rip up the VSS grids +pdn_obj.ripUp(VSS_net)",Rip up the VSS grids +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input2' as mentioned in the prompt +inst = block.findInst('input2') +#Set the location to coordinates (22500, 33459) +inst.setLocation(22500,33459)","Set the location of the instance named 'input2' to coordinates (22500, 33459)." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""resp_msg[15]"" +port = block.findBTerm('resp_msg[15]') +# Find the net with name ""req_msg[10]"" +net = block.findNet('req_msg[10]') +# Connect the port and the net +port.connect(net)",Establish a connection between the port 'resp_msg[15]' and the net named 'req_msg[10]'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""resp1_3_msg[15]"" +port = block.findBTerm('resp1_3_msg[15]') +# Find the net with name ""req_msg[10]"" +net = block.findNet('req_msg[10]') +# Connect the port and the net +port.connect(net)",Establish a connection between the port 'resp1_3_msg[15]' and the net named 'req_msg[10]'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""resp1_3_msg[12]"" +port = block.findBTerm('resp1_3_msg[12]') +# Find the net with name ""req_msg[12]"" +net = block.findNet('req_msg[12]') +# Connect the port and the net +port.connect(net)",Establish a connection between the port 'resp1_3_msg[12]' and the net named 'req_msg[12]'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""resp_msg[15]"" +port = block.findBTerm('resp_msg[15]') +# Disconnect the port +port.disconnect()",Remove the connection of the port 'resp_msg[15]' from its associated nets. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""sram_132[15]"" +port = block.findBTerm('sram_132[15]') +# Disconnect the port +port.disconnect()",Remove the connection of the port 'sram_132[15]' from its associated nets. +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VDD_net = design.getBlock().findNet(""VDD"") +# Rip up the VDD grids +pdn_obj.ripUp(VDD_net)",How can I rip up the existing VDD power grid so I can reconstruct PDN? +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VDD_net = design.getBlock().findNet(""VDD"") +# Rip up the VDD grids +pdn_obj.ripUp(VDD_net)",How can I remove the existing VDD power grid? +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VSS net +VDD_net = design.getBlock().findNet(""VSS"") +# Rip up the VSS grids +pdn_obj.ripUp(VSS_net)",How can I rip up the existing VSS power grid so I can reconstruct PDN? +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VSS net +VDD_net = design.getBlock().findNet(""VSS"") +# Rip up the VSS grids +pdn_obj.ripUp(VSS_net)",How can I remove the existing VSS power grid? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input3' as mentioned in the prompt +inst = block.findInst('input3') +#Set the placing location of the instance to (18000,26999) +inst.setLocation(18000,26999)","Set the location of the instance 'input3' to (18000,26999) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst('input1') +#Set the location of the instance with X Coordinate 22500 and Y Coordinate as 33459 +inst.setLocation(22500,33459)","Set the location of the instance 'input1' to (22500,33459) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input3' as mentioned in the prompt +inst = block.findInst('input3') +#Set the placing location of the instance to (2.5,1.8) in micron +inst.setLocation(int(2.5*block.getDbUnitsPerMicron()),int(1.8*block.getDbUnitsPerMicron()))","Set the location of the instance 'input3' to (2.5, 1.8) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micron +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micron +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Move the instance 'split30' to (10.81, 3.6) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 3.6) in micron +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (10.81, 3.6) in micron?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (20, 3.6) in micron +inst.setLocation(int(20*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (20, 3.6) in micron?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst('input1') +#Set the location of the instance with X Coordinate 22500 and Y Coordinate as 33459 +inst.setLocation(22500,33459)","How can I set the location of the instance 'input1' to (22500,33459) in OpenDB unit?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst('input1') +#Set the location of the instance with X Coordinate 22500 and Y Coordinate as 33459 +inst.setLocation(22500,33459)","Show me how I can set the location of the instance 'input1' to (22500,33459) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 9.18) in micron +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(9.18*block.getDbUnitsPerMicron()))","Show me how I can move the instance '_11991_' to (10.81, 9.18) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_temp_inst_' as mentioned in the prompt +inst = block.findInst('_temp_inst_') +#Set the placing location of the instance to (3.18, 9.18) in micron +inst.setLocation(int(3.18*block.getDbUnitsPerMicron()),int(9.18*block.getDbUnitsPerMicron()))","Show me how I can move the instance '_temp_inst_' to (3.18, 9.18) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'and_no_123' as mentioned in the prompt +inst = block.findInst('and_no_123') +#Set the placing location of the instance to (4.14, 41.4) in micron +inst.setLocation(int(4.14*block.getDbUnitsPerMicron()),int(41.4*block.getDbUnitsPerMicron()))","Show me how I can move the instance 'and_no_123' to (4.14, 41.4) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'and_no_123' as mentioned in the prompt +inst = block.findInst('and_no_123') +#Set the placing location of the instance to (4.14, 41.4) in um +inst.setLocation(int(4.14*block.getDbUnitsPerMicron()),int(41.4*block.getDbUnitsPerMicron()))","Show me how I can move the instance 'and_no_123' to (4.14, 41.4) in um" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in um +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in um" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in um +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Move the instance 'split30' to (10.81, 3.6) in um" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 3.6) in um +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (10.81, 3.6) in um?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (20, 3.6) in um +inst.setLocation(int(20*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (20, 3.6) in um?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in micrometer" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Move the instance 'split30' to (10.81, 3.6) in micrometer" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setLocation(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (10.81, 3.6) in micrometer?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (20, 3.6) in micrometer +inst.setLocation(int(20*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (20, 3.6) in micrometer?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input3' as mentioned in the prompt +inst = block.findInst('input3') +#Set the placing location of the instance to (18000,26999) +inst.setOrigin(18000,26999)","Set the location of the instance 'input3' to (18000,26999) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst('input1') +#Set the location of the instance with X Coordinate 22500 and Y Coordinate as 33459 +inst.setOrigin(22500,33459)","Set the location of the instance 'input1' to (22500,33459) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input3' as mentioned in the prompt +inst = block.findInst('input3') +#Set the placing location of the instance to (2.5,1.8) in micron +inst.setOrigin(int(2.5*block.getDbUnitsPerMicron()),int(1.8*block.getDbUnitsPerMicron()))","Set the location of the instance 'input3' to (2.5, 1.8) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micron +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst('input1') +#Set the location of the instance with X Coordinate 22500 and Y Coordinate as 33459 +inst.setOrigin(22500,33459)","Show me how I can set the location of the instance 'input1' to (22500,33459) in OpenDB unit" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 9.18) in micron +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(9.18*block.getDbUnitsPerMicron()))","Show me how I can move the instance '_11991_' to (10.81, 9.18) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_temp_inst_' as mentioned in the prompt +inst = block.findInst('_temp_inst_') +#Set the placing location of the instance to (3.18, 9.18) in micron +inst.setOrigin(int(3.18*block.getDbUnitsPerMicron()),int(9.18*block.getDbUnitsPerMicron()))","Show me how I can move the instance '_temp_inst_' to (3.18, 9.18) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'and_no_123' as mentioned in the prompt +inst = block.findInst('and_no_123') +#Set the placing location of the instance to (4.14, 41.4) in micron +inst.setOrigin(int(4.14*block.getDbUnitsPerMicron()),int(41.4*block.getDbUnitsPerMicron()))","Show me how I can move the instance 'and_no_123' to (4.14, 41.4) in micron" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'and_no_123' as mentioned in the prompt +inst = block.findInst('and_no_123') +#Set the placing location of the instance to (4.14, 41.4) in um +inst.setOrigin(int(4.14*block.getDbUnitsPerMicron()),int(41.4*block.getDbUnitsPerMicron()))","Show me how I can move the instance 'and_no_123' to (4.14, 41.4) in um" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in um +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in um" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Set the location of the instance 'split30' to (10.81, 3.6) in micrometer" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'split30' as mentioned in the prompt +inst = block.findInst('split30') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","Move the instance 'split30' to (10.81, 3.6) in micrometer" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (10.81, 3.6) in micrometer +inst.setOrigin(int(10.81*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (10.81, 3.6) in micrometer?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name '_11991_' as mentioned in the prompt +inst = block.findInst('_11991_') +#Set the placing location of the instance to (20, 3.6) in micrometer +inst.setOrigin(int(20*block.getDbUnitsPerMicron()),int(3.6*block.getDbUnitsPerMicron()))","How can I move the instance '_11991_' to (20, 3.6) in micrometer?" diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.xlsx new file mode 100644 index 0000000..f218ac1 Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/circuit_modification.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.csv new file mode 100644 index 0000000..0d6505b --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.csv @@ -0,0 +1,6351 @@ +code,prompt +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() + +# Retrieve all instances present in the design block +insts = block.getInsts() + +# Initialize an empty list to store the names of library cell type for each instance +masters_list = [] + +# Iterate over each instance in the design block +for inst in insts: + # Retrieve the library cell type of the current instance + master_type = inst.getMaster() + # Get the name of the library cell type + master_type_name = master_type.getName() + # Append the name of the library cell type to the list + masters_list.append(master_type_name) + +# Return the list containing the names of library cell type for every instance +return masters_list",Give me the names of library cell type of every instance +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +loc = [] +for inst in insts: + # Append the location of the instance to the list + loc.append(inst.getLocation()) +return loc",Give methe location of every instance in the design and return it in a list called loc. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +placement_status_with_name = {} +# Iterate over each instance in the design block +for inst in insts: + # Get the name of particular instance + name = inst.getName() + # Get the placement status of the instance + status = inst.getPlacementStatus() + # Add the respective instance name and its status + placement_status_with_name[name] = status +return placement_status_with_name",Get the name of every instance with its placement status as a dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +placed_instances = [] +# Iterate over each instance in the design block +for inst in insts: + # Check if this instance is placed + if inst.isPlaced()==True: + # Append the instance name to the array + placed_instances.append(inst.getName()) +return placed_instances",Get the names of every instance which are placed and return a list of names +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +level_of_instance = {} +# Iterate over each instance in the design block +for inst in insts: + # Retrieve the name of the instance and its level, then store it in the dictionary + level_of_instance[inst.getName()] = inst.getLevel() +return level_of_instance",Get the level of all instances with the instance name as a dictionary. Key of the dictionary is name of the instance and value is the level of the instance +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +const_name= [] +# Iterate over each instance in the design block +for inst in insts: + # Append the Const name of the instance + const_name.append(inst.getConstName()) +return const_name",Get all the Constant names of the instances and return as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +print("" name | net_type | pin&wire_capacitance"") +# Retrieve all nets present in the design block +nets = block.getNets() +# Iterate over each net in the design block +for net in nets: + # Get the net capacitance + pin_and_wire_cap = timing.getNetCap(net, corner, timing.Max) + # Get the name of the net + net_name = net.getName() + # Get the signal Type of the net + net_type = net.getSigType() + print(f""{net_name:<12}| {net_type:<9}| {pin_and_wire_cap:19.4e}"")","Write a code to Print the name of the net, its net type, and the wire capacitance of all the nets" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +print("" name | rise_arrival_time | fall_arrival_time | rise_slack | fall_slack | slew"") +# Iterate over each instance in the design block +for inst in insts: + # Get the pins associated with the instance + inst_ITerms = inst.getITerms() + # Iterate through all the pins + for pin in inst_ITerms: + # Check if the pin is in supply + if design.isInSupply(pin): + continue + # Get the pin name + pin_name = design.getITermName(pin) + # Get the pin rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Get the pin fall arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Get the pin rise slack + pin_rise_slack = timing.getPinSlack(pin, timing.Fall, timing.Max) + # Get the pin fall slack + pin_fall_slack = timing.getPinSlack(pin, timing.Rise, timing.Max) + # Get the pin slew + pin_slew = timing.getPinSlew(pin) + print(f""{pin_name:<12} | {pin_rise_arr:17.4e} | {pin_fall_arr:17.4e} | {pin_rise_slack:10.4e} | {pin_fall_slack:10.4e} | {pin_slew:6.4e}"") ","Write a code to print all the pin names, rising arrival time, fall arrival time, rise stack, fall stack and slew of all the pins" +"#Get the OpenROAD database +db = ord.get_db() +#Get the number of library cell types +return db.getNumberOfMasters()",Get the number of library cells in the library +"# Get the design block +block = ord.get_db_block() +# Get the die area of the design +area = block.getDieArea() +# Get the width and height of the die area +dx = area.dx() +dy = area.dy() +# Calculate the die area +die_area = dx*dy +# Return the calculated die area +return die_area",Get the die area +"# Get the design block +block = ord.get_db_block() +# Get the core area of the design +area = block.getCoreArea() +# Get the width and height of the core area +dx = area.dx() +dy = area.dy() +# Calculate the core area +core_area = dx*dy +# Return the calculated core area +return core_area",Get the core area +"# Get the design block +block = ord.get_db_block() +# Report global connection of the design +global_connection = block.reportGlobalConnect() +# Return the global connections +return global_connection",Report all the global connection rules +"# Get the design block +block = ord.get_db_block() +# Initialize a variable to store the total number of pins +total_pins = 0 +# Get instances +insts = block.getInsts() + +# Iterate over instances +for inst in insts: + # Add the number of pins of the instance to the total + total_pins += len(inst.getITerms()) + +# Return the total number of pins +return total_pins",Get the total number of pins +"# Get the design block +block = ord.get_db_block() +# Get instances +insts = block.getInsts() +# Initialize a list to store instance names +inst_name =[] + +# Iterate over instances and append their names to the list +for inst in insts: + inst_name.append(inst.getName()) + +# Return the list of instance names +return inst_name",List all the instances name +"# Get the design block +block = ord.get_db_block() +# Initialize a list to store clock nets +clock_nets = [] +# Get all nets +nets = block.getNets() +# Iterate over nets +for net in nets: + # Check if the net is a CLOCK net + if net.getSigType() == 'CLOCK': + # Check if the net is a CLOCK net + clock_nets.append(net) +# Check if CLOCK nets exist +if len(clock_nets) > 0: + return True +else: + return False",Check if the design has any clock nets +"# Get the design block +block = ord.get_db_block() +# Initialize variables to count power and ground nets +power_nets = 0 +ground_nets = 0 +# Get all nets +nets = block.getNets() +# Iterate over nets +for net in nets: + # Check if the net is a POWER net + if net.getSigType() == 'POWER': + power_nets += 1 + # Check if the net is a GROUND net + elif net.getSigType() == 'GROUND': + ground_nets += 1 +# Return the counts of power and ground nets +return power_nets, ground_nets",Get the total number of power and ground nets +"# Get the chip associated with the design's block. + +# Retrieve the design block +block = design.getBlock() + +# Get the chip associated with the design block. +chip = block.getChip() + +# Return the chip associated with the design block. +return chip ",Give me the chip of a given block +"# Get the nets in a given block + +# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Return the list of nets +return nets",Get all nets in a given block +design.getBlock().getName(),Get the name of the design block +"# Get the logic ports for a given block + +# Get the design block +block = design.getBlock() + +# Get all logic ports +logic_ports = block.getLogicPorts() + +# Return the list of logic ports +return logic_ports",Get the logic ports for a given block +"# Get the location of all instances +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through all instances +for inst in insts: + # Print the instance name and its location + print(inst.getName(), ""Location:"", inst.getLocation())",Get the location of all instances +"# Check if the instance 'FILLER_0_0_1' is placed or not + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check placement status +inst_name = 'FILLER_0_0_1' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",Check if the instance 'FILLER_0_0_1' placed or not +"# Get the children of 'FILLER_0_0_1' instance + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance whose children are to be retrieved +inst_name = 'FILLER_0_0_1' + +# Initialize a list to store children instances +children = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Get the children instances of the target instance + children = inst.getChildren() + break + +# Return the list of children instances +return children",Get the children of 'FILLER_0_0_1' instance +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Initialize variables to track the net with the maximum capacitance +max_cap_net = None +max_cap = float('-inf') +# Iterate over nets +for net in nets: + # Get the total capacitance of the net + cap = timing.getNetCap(net, corner, timing.Max) + # Check if the capacitance of the current net is greater than the maximum capacitance found so far + if cap > max_cap: + # Update the maximum capacitance and the corresponding net + max_cap = cap + max_cap_net = net +# Return the net with the maximum capacitance +return max_cap_net.getName()",Identify the nets with the highest capacitance +"# Get the design block +block = ord.get_db_block() +# Find the instance named ""split30"" +return block.findInst(""split30"")",Find instance split30 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Define the fanout threshold +gt_fanout = 10 +# Initialize a list to store nets with fanout greater than the threshold +net_fanout = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) > gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) +# Return the list of nets with fanout greater than the threshold +return net_fanout",Give me a list of nets with a fanout greater than 10 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Initialize variables to store maximum fanout and its corresponding net +max_fanout = 0 +# Lists to store net names and their corresponding fanouts +net_fanout_list = [] +net_name_list = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Append the net name and its fanout to the respective lists + net_name_list.append(net_name) + net_fanout_list.append(len(output_pins)) +# Find the maximum fanout +max_fanout = max(net_fanout_list) +# Find the index of the net with the maximum fanout +max_fanout_index = net_fanout_list.index(max_fanout) +# Get the name of the net with the maximum fanout +max_fanout_net = net_name_list[max_fanout_index] +# Return the net with the maximum fanout +return max_fanout_net",Give me a list of nets with the maximum fanout +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Initialize a list to store unique name of library cell types +masters_list = [] +# Iterate over instances +for inst in insts: + # Get the master associated with the instance + mast = inst.getMaster() + mast_name = mast.getName() + # Check if the library cell name is not already in the list + if mast_name not in masters_list: + # Append the library cell name to the list + masters_list.append(mast_name) +# Return the list of unique library cell names +return masters_list",List all the library cells used +"# Get the design block +block = ord.get_db_block() +# Get the total number of connections (nets) +total_connections = len(block.getNets()) +# Return the total number of connections +return total_connections",Get the total number of connections (nets) +"# Get all the input/output nets for a given block + +# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Initialize a list to store input/output nets +io_nets = [] + +# Iterate through all nets +for net in nets: + # Check if the net is an input/output net + if net.isIO(): + # If it's an input/output net, add it to the list + io_nets.append(net) + +# Return the list of input/output nets +return io_nets",get all the input output nets for a given block +"# Get a list of all the output pins + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store output pins +output_pins_list = [] + +# Iterate through all instances +for inst in insts: + # Get all input pins (ITerms) of the instance + pins = inst.getITerms() + # Iterate through all input pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # If it's an output signal, add it to the list + output_pins_list.append(pin) + +# Return the list of output pins +return output_pins_list",get a list of all the output pins +"#Give me all nets connecting to the instance '_411_' + +# Instance name to search for +inst_name = ""_411_"" + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a variable to store the nets of the instance +nets = None + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Get all pins (ITerms) of the instance and extract their associated nets + nets = [pin.getNet() for pin in inst.getITerms()] + break + +# Return the nets of the instance +return nets +",Give me all nets connecting to the instance '_411_' +"# Get weights of all the instances + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store weights of instances +inst_weight_dict = {} + +# Iterate through all instances +for inst in insts: + # Get the instance name + name = inst.getName() + # Check if the instance name is not already in the dictionary + if name not in inst_weight_dict: + # If not, add the instance name and its weight to the dictionary + inst_weight_dict[name] = inst.getWeight() + +# Return the dictionary containing weights of instances +return inst_weight_dict",get Weights of all the instances +"# Get length and width of the Bounding Box of the instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Get the length and width of the Bounding Box of the instance +length = inst.getBBox().getLength() +width = inst.getBBox().getWidth() + +# Return the length and width +return (length, width) +",get length and width of the bounding Box of the instance ''_411_' +"# Get source type of all the instances on level 1 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store source types of instances on level 1 +lvl1_inst_src_type = {} + +# Iterate through all instances +for inst in insts: + # Check if the instance is on level 1 + if inst.getLevel() == 1: + # Add the instance name and its source type to the dictionary + lvl1_inst_src_type[inst.getName()] = inst.getSourceType() + +# Return the dictionary containing source types of instances on level 1 +return lvl1_inst_src_type +",get source type of all the instance on level 1 +"# Set the placement status of the instance '_411_' to 'UNPLACED' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the placement status of the instance to 'UNPLACED' +inst.setPlacementStatus('UNPLACED') +",set the placement Status of the instance '_411_' to 'UNPLACED' +"# Get all the blockages + +# Get the design block +block = design.getBlock() + +# Return all blockages +return block.getBlockages()",get all the blockages +"# Reset the tapcell in the design + +# Get the tapcell in the design +tapcell = design.getTapcell() + +# Reset the tapcell +tapcell.reset()",reset the tapcell in the design +"# Retrieve the capacitor-coupled segments + +# Get the design block +block = design.getBlock() + +# Return the capacitor-coupled segments +return block.getCCSegs()",retrieve the capacitor-coupled segments +"# Get the sites of rows + +# Get the design block +block = design.getBlock() + +# Get all rows +rows = block.getRows() + +# Initialize a dictionary to store row names and their corresponding sites +row_site_dict = {} + +# Iterate through all rows +for row in rows: + # Add the row name and its site to the dictionary + row_site_dict[row.getName()] = row.getSite() + +# Return the dictionary containing row names and their sites +return row_site_dict",get the sites of rows +"# Get the height and width of the sites of each row + +# Get the design block +block = design.getBlock() + +# Get all rows +rows = block.getRows() + +# Initialize a dictionary to store row names and their corresponding site dimensions +row_site_dict = {} + +# Iterate through all rows +for row in rows: + # Check if the row has a site + if row.getSite(): + # Add the row name and its site dimensions to the dictionary + row_site_dict[row.getName()] = [row.getSite().getHeight(), row.getSite().getWidth()] + +# Return the dictionary containing row names and their site dimensions +return row_site_dict",get the height and width of the sites of each row +"# Get the location, orientation, direction, and spacing of rows + +# Get the design block +block = design.getBlock() + +# Get all rows +rows = block.getRows() + +# Iterate through all rows +for i in range(len(rows)): + row = rows[i] + # Print row information + print(""Row"", i, row.getName()) + print(""Location:"", row.getOrigin()) + print(""Rotation:"", row.getOrient()) + print(""Direction:"", row.getDirection()) + print(""Block spacing:"", row.getSpacing()) +","get the location, rotation, direction and spacing of rows" +"# Get the rows with hybrid sites + +# Get the design block +block = design.getBlock() + +# Get all rows +rows = block.getRows() + +# Initialize a list to store rows with hybrid sites +hybrid_row_site = [] + +# Iterate through all rows +for i in range(len(rows)): + row = rows[i] + site = row.getSite() + # Check if the site is hybrid + if site.isHybrid(): + # Append the row and its site to the list + hybrid_row_site.append((row, site)) + +# Return the list of rows with hybrid sites +return hybrid_row_site",get the rows with hybrid sites +"# Get all the instances and their halos + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store instances and their halos +inst_halos = {} + +# Iterate through all instances +for inst in insts: + # Add the instance name and its halo to the dictionary + inst_halos[inst.getName()] = inst.getHalo() + +# Return the dictionary containing instances and their halos +return inst_halos",get all the instances and there halos +"# Get the instances and their respective regions + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store instances and their regions +inst_regions = {} + +# Iterate through all instances +for inst in insts: + # Add the instance name and its region to the dictionary + inst_regions[inst.getName()] = inst.getRegion() + +# Return the dictionary containing instances and their regions +return inst_regions",get the instances and their respective regions +"# Get all the do not touch instances and set do not touch to true if false for instances + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store do not touch instances +do_not_touch_elements = {} + +# Iterate through all instances +for inst in insts: + # Check if the instance is marked as do not touch + if inst.isDoNotTouch(): + # Add the instance to the dictionary + do_not_touch_elements[inst.getName()] = inst + else: + # Set do not touch to true for instances marked as false + inst.setDoNotTouch(True) + +# Return the dictionary containing do not touch instances +return do_not_touch_elements",get the all the do not touch instance and set do not touch to true if false for instances +"# Set the EcoCreate and EcoDestroy for instance '_411_' to true + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Set EcoCreate and EcoDestroy to true +inst.setEcoCreate(True) +inst.setEcoDestroy(True) + +# Return the modified instance +return inst",set the EcoCreate and EcoDestroy for instance '_411_' true +"# Mark the first output nets of the instances '_411_' and 'input1' + +# Get the design block +block = design.getBlock() + +# Find the instances '_411_' and 'input1' +inst1 = block.findInst('_411_') +inst2 = block.findInst('input1') + +# Mark the first output net of instance '_411_' +inst1.getFirstOutput().getNet().setMark(True) + +# Mark the first output net of instance 'input1' +inst2.getFirstOutput().getNet().setMark(True) +",mark the first output nets of the instances '_411_' and 'input1' +"# Get the nets that are disconnected from RC network + +# Get the design block +block = design.getBlock() + +# Get all the nets +nets = block.getNets() + +# Initialize a list to store RC disconnected nets +rc_disconnected_nets = [] + +# Iterate through all the nets +for net in nets: + # Check if the net is RC disconnected + if net.isRCDisconnected(): + # Add the net to the list + rc_disconnected_nets.append(net) + +# Return the list of RC disconnected nets +return rc_disconnected_nets",Get the nets that are disconnected from RC network +"# Disconnect the nets of the instance 'input1' from the RC network + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'input1' +inst = block.findInst('input1') + +# Get the pins of the instance +pins = inst.getITerms() + +# Iterate through the pins +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + if net: + # Set the RC disconnected flag for the net + net.setRCDisconnected(True) +",Disconnect the nets of the instance 'input1' from the RC network +"# Get the points of the placement bounding box of the library cell of the instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the library cell associated with the instance +master = inst.getMaster() + +# Get the placement bounding box of the library cell +placement_boundary = master.getPlacementBoundary() + +# Return the points of the placement bounding box +return placement_boundary.getPoints() +",get the points of the placement bounding box of the library cell of the instance '_411_' +"# Clear user flags of instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Clear user flags 1, 2, and 3 of the instance +inst.clearUserFlag1() +inst.clearUserFlag2() +inst.clearUserFlag3()",clear user flags of instance '_411_' +"# Check if the instance '_411_' is marked as an end cap cell. + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Check if the instance is marked as an end cap +return inst.isEndCap()",Check if the instance '_411_' is marked as an end cap cell. +"# Map nets to the wires + +# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Initialize a dictionary to store net-wire mappings +net_wire_dict = {} + +# Iterate through all nets +for net in nets: + # Get the name of the net + net_name = net.getName() + + # If the net name is not already in the dictionary, initialize an empty list + if net_name not in net_wire_dict: + net_wire_dict[net_name] = [] + + # Append the wire connected to the net to the list in the dictionary + net_wire_dict[net_name].append(net.getWire()) + +# Return the net-wire dictionary +return net_wire_dict",map nets to the wires +"# Get the MTerms of the master cell of the instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Return the MTerms +return mterms",get the MTerms of the master cell of the instance '_411_' +"# Get the IoType of the pins of the instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",get the IoType of the pins of the instance '_411_' +"block = design.getBlock() +insts = block.getInsts() +inst_list = [] +for inst in insts: + if not inst.getMaster().isCore(): + inst_list.append(inst) +return inst_list",get the instances whose masters are not of type CORE +"# Get the number of masks of each layer + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the number of masks for each layer +num_masks = {} + +# Iterate through all layers +for layer in layers: + # Store the number of masks for each layer + num_masks[layer.getName()] = layer.getNumMasks() + +# Return the dictionary containing the number of masks for each layer +return num_masks",get the number of masks of each layer +"# Get the clearance measure + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return the clearance measure +return tech.getClearanceMeasure()",get the measure system +"# Check LEF USEMINSPACING is set or not + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return whether UseMinSpacingObs is set in the technology +return tech.getUseMinSpacingObs()",Check LEF USEMINSPACING is set or not +"# Get the layers if they are set as isRectOnly + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a list to store layers are set as RectOnly +rect_layers = [] + +# Iterate through all layers +for layer in layers: + # Check if the layer is set as RectOnly + if layer.isRectOnly(): + # Append the rectangle-only layer to the list + rect_layers.append(layer) + +# Return the list of rectangle-only layers +return rect_layers",Get the layers if they are set as isRectOnly +"# Get the alias of all the layers + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the Alias of each layer +layer_alias = {} + +# Iterate through all layers +for layer in layers: + # Store the Alias of each layer + layer_alias[layer.getName()] = layer.getAlias() + +# Return the dictionary containing the Alias of all layers +return layer_alias",Get the alias of all the layers +"# Set the alias of the layers by the name convention ''layer i"" where i is the index of the layer + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the Alias of each layer +layer_alias = {} + +# Iterate through all layers +for layer in layers: + # Construct the Alias using the layer index + alias = ""Layer "" + str(layer.getNumber()) + + # Set the Alias of the layer + layer.setAlias(alias) + + # Store the Alias of the layer in the dictionary + layer_alias[layer.getName()] = alias + +# Return the dictionary containing the updated Alias of layers +return layer_alias +","Set the Alias of the layers by the name convention ''layer i"" where i is the index of the layer" +"# Get LEF version + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return the LEF version of the technology +return tech.getLefVersion()",Get LEF version +"# Get LEF version as a string + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return the LEF version of the technology as a string +return tech.getLefVersionStr()",Get LEF version as a string +"# Get the resistance of all the layers + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the resistance of each layer +layer_resistance = {} + +# Iterate through all layers +for layer in layers: + # Get the resistance of the layer and store it in the dictionary + layer_resistance[layer.getName()] = layer.getResistance() + +# Return the dictionary containing the resistance of each layer +return layer_resistance",Get the resistance of all the layers +"# Get edge capacitance of all the layers + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the edge capacitance of each layer +layer_edge_capacitance = {} + +# Iterate through all layers +for layer in layers: + # Get the edge capacitance of the layer and store it in the dictionary + layer_edge_capacitance[layer.getName()] = layer.getEdgeCapacitance() + +# Return the dictionary containing the edge capacitance of each layer +return layer_edge_capacitance",get edge capacitance of all the layers +"# Get the upper and lower layer of the layer 'metal5' + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Find the layer 'metal5' +layer = tech.findLayer('metal5') + +# Return the upper and lower layer of 'metal5' +return (layer.getUpperLayer(), layer.getLowerLayer())",get the upper and lower layer of the layer 'metal5' +"# Check if instance '_411_' is buffer and if it is an End Cap cell +block = design.getBlock() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Get the master of the instance +master = inst.getMaster() + +# Check if the design is buffer for the master and if the master is End Cap +return design.isBuffer(master) and master.isEndCap()",Check if instance '_411_' is buffer and if it is an End Cap cell +"# Get the instances whose masters are of type sequential and make the master of instance '_411_' sequential + +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# List to store sequential instances +seq_insts = [] + +# Iterate through instances +for inst in insts: + # Get the master of the instance + master = inst.getMaster() + + # Check if the instance is '_411_' + if inst.getName() == '_411_': + # Make the master of instance '_411_' sequential + master.setSequential(True) + + # Check if the master is of type sequential + if master.isSequential(): + seq_insts.append(inst) + +# Return sequential instances +return seq_insts +",Get the instances whose masters are of type sequential and make the master of instance '_411_' sequential +"# Check if the instance '411' has any pin set as clocked +block = design.getBlock() + +# Find the instance '411' +inst = block.findInst('_411_') + +# Get all pins of the instance +pins = inst.getITerms() + +# List to store pins set as clocked +clocked_ports = [] + +# Check if any pin is set as clocked +for pin in pins: + if pin.isClocked(): + clocked_ports.append(pin) + +# Return clocked ports +return clocked_ports",Check if the instance '411' has any pin set as clocked +"# Display the location, orient, direction, and spacing of each row +block = design.getBlock() +rows = block.getRows() + +# Print table header +print(""{:<15} {:<15} {:<15} {:<15}"".format(""Row Name"", ""Location"", ""Direction"", ""Spacing"")) + +# Print data in a table format +for row in rows: + location = str(row.getOrigin()) + direction = str(row.getDirection()) + spacing = str(row.getSpacing()) + + print(""{:<15} {:<15} {:<15} {:<15}"".format(row.getName(), location, direction, spacing))","Display the location, orient, direction, and spacing of each row" +"# Get the rows with 'MX' orient and get the instances and the first output pin of all instances +block = design.getBlock() +rows = block.getRows() +insts = block.getInsts() + +# Initialize dictionaries to store the results +output_pins_dict = {} +MX_rows = [] + +# Iterate over rows to find those with 'MX' rotation +for row in rows: + if row.getOrient() == ""MX"": + MX_rows.append(row) + +# Iterate over instances to find their output pins +for inst in insts: + if inst.getFirstOutput(): + output_pins_dict[inst.getName()] = inst.getFirstOutput() + +# Return the rows with 'MX' orientation and output pins of instances +return (MX_rows, output_pins_dict)",Get the rows with 'MX' rotation and get the instances and the first output pin of all instances. +"# Get all the instances and their halos and regions in a dictionary +block = design.getBlock() +insts = block.getInsts() +inst_halo_region_dict = {} + +# Iterate over instances to collect their halos and regions +for inst in insts: + inst_halo_region_dict[inst.getName()] = (inst.getHalo(), inst.getRegion()) + +# Return the dictionary with instance names as keys and a tuple of halo net and region as values +return inst_halo_region_dict",Get all the instances and their halos and regions in a dictionary with the instance name as the key and a tuple of halo net and region as value +"# Get the all the do not touch instances and set do not touch to true for pad instances +# Also, set the EcoCreate and EcoDestroy for instance '_411_' to True. + +block = design.getBlock() +insts = block.getInsts() +dnt_insts = [] + +# Iterate over instances to set 'Do Not Touch' for pads and collect do not touch instances +for inst in insts: + if inst.isPad(): + inst.setDoNotTouch(True) + + if inst.isDoNotTouch(): + dnt_insts.append(inst) + + #set the EcoCreate and EcoDestroy for instance '_411_' true. + if inst.getName() == ""_411_"": + inst.setEcoCreate(True) + inst.setEcoDestroy(True) + +return dnt_insts",Get the all the do not touch instances and set do not touch to true for pad instances and set the EcoCreate and EcoDestroy for instance '_411_' to True. +"# Mark the first output nets of the instances '411' and 'input1' and set RC disconnected to True for the nets. + +# Get the block of the design +block = design.getBlock() + +# Find the instances '411' and 'input1' +inst1 = block.findInst(""_411_"") +inst2 = block.findInst(""input1"") + +# Mark the first output nets of the instances and set RC disconnected true for the nets +inst1.getFirstOutput().getNet().setMark(True) +inst2.getFirstOutput().getNet().setMark(True) + +# Set RC disconnected true for the net of the first output of instance '411' +inst1.getFirstOutput().getNet().setRCDisconnected(True) + +# Set RC disconnected true for the net of the first output of instance 'input1' +inst2.getFirstOutput().getNet().setRCDisconnected(True)",Mark the first output nets of the instances '411' and 'input1' and set RC disconnected to True for the nets. +"# Set RC disconnected true for the nets of the instance 'input1' +block = design.getBlock() +inst = block.findInst('input1') +nets = [pin.getNet() for pin in inst.getITerms()] +for net in nets: + if net: + net.setRCDisconnected(True) + +# Get the upper-left, lower-left, lower-right, upper-right coordinates of the placement bounding box of the master cell of the instance '411' +placement_boundary = inst.getMaster().getPlacementBoundary() +coordinates = { + ""ul"": placement_boundary.ul(), + ""ll"": placement_boundary.ll(), + ""lr"": placement_boundary.lr(), + ""ur"": placement_boundary.ur() +} +return coordinates","Set the RC disconnected true for the nets of the instance 'input1' and get the upper-left, lower-left, lower-right, upper-right coordinates of the placement bounding box of the master cell of the instance '411'." +"# Get the current block of the design +block = design.getBlock() + +# Find the instance with the name '_411_' +inst = block.findInst('_411_') + +# Get the placement bounding box of the master cell of the instance +placement_boundary = inst.getMaster().getPlacementBoundary() + +# Get the points of the placement bounding box +points = placement_boundary.getPoints() + +# Clear user flag 1 of the instance +inst.clearUserFlag1() + +# Clear user flag 2 of the instance +inst.clearUserFlag2() + +# Clear user flag 3 of the instance +inst.clearUserFlag3() + +# Return the points of the placement bounding box +return points",Get the points of the placement bounding box of the master cell of the instance '411' and clear user flags of instance '_411_'. +"# Get the current block of the design +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store coordinates for each master cell +coordinates = {} + +# Iterate through each instance +for inst in insts: + # Get the master cell of the instance + master = inst.getMaster() + + # Get the placement bounding box of the master cell + placement_boundary = master.getPlacementBoundary() + + # Check if the master cell name is not already in the coordinates dictionary + if master.getName() not in coordinates: + # Store the center x, y coordinates, and minimum and maximum x, y coordinates in the dictionary + coordinates[master.getName()] = { + ""center"": [placement_boundary.xCenter(), placement_boundary.yCenter()], + ""min"": [placement_boundary.xMin(), placement_boundary.yMin()], + ""max"": [placement_boundary.xMax(), placement_boundary.yMax()] + } + +# Return the dictionary containing coordinates for each master cell +return coordinates","Get the center x, y and minimum and maximum x, y coordinates of the placement bounding box of the master cell of the all instance." +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Dictionary to store spacing and number of masks for each layer +spacing_and_mask = {} + +# Iterate through each layer in the technology +for layer in layers: + # Store the spacing and number of masks for the current layer in the dictionary + spacing_and_mask[layer.getName()] = { + ""spacing"": layer.getSpacing(), + ""masks"": layer.getNumMasks() + } + +# Return the dictionary containing spacing and number of masks for each layer +return spacing_and_mask +",Get the spacing and the number of masks of each layer +"# Get the current block of the design +block = design.getBlock() + +# Get all blockages +blockages = block.getBlockages() + +# Get all nets +nets = block.getNets() + +# List to store RC disconnected nets +rc_disconnected_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is RC disconnected + if net.isRCDisconnected(): + # Append the net to the list of RC disconnected nets + rc_disconnected_nets.append(net) + +# Find the instance 'rebuffer7' +inst = block.findInst('rebuffer7') + +# Get the MTerms of the master cell of instance 'rebuffer7' +mterms = inst.getMaster().getMTerms() + +# Return a tuple containing blockages, RC disconnected nets, and MTerms +return (blockages, rc_disconnected_nets, mterms)","Get all the blockages and get the nets that are RC disconnected, followed by getting the MTerms of the master cell of the instance 'rebuffer7'." +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Define the direction for the layers +direction = 'HORIZONTAL' + +# List to store horizontal tech layers and their capacitance +horizontal_layers = [] + +# Iterate through each layer in the technology +for layer in layers: + # Check if the layer direction is HORIZONTAL + if layer.getDirection() == direction: + # Append the layer and its capacitance to the list of horizontal layers + horizontal_layers.append((layer, layer.getCapacitance())) + +# Retrieve the clearance measure +clearance_measure = tech.getClearanceMeasure() + +# Get the setting of UseMinSpacingObs in the tech file +min_space_obs = tech.getUseMinSpacingObs() + +# Construct a dictionary containing horizontal layers, clearance measure, and minimum spacing obstacle +result = { + ""horizontal_layers"": horizontal_layers, + ""clearance_measure"": clearance_measure, + ""min_space_obs"": min_space_obs +} + +# Return the result dictionary +return result","Get the horizontal layers and their capacitance, then retrieve the clearance measure system and check if UseMinSpacingObs is set for this technology" +"# Get the current block of the design +block = design.getBlock() + +# Get rows and nets +rows = block.getRows() +nets = block.getNets() + +# Dictionary to store row information with row index as key +row_info_dict = {} + +# Dictionary to store sites of rows with row name as key +row_site_dict = {} + +# Dictionary to map nets to wires +net_wire_dict = {} + +# Iterate through each row +for i in range(len(rows)): + row = rows[i] + # Store row information in the row_info_dict + row_info_dict[i] = { + ""Location"": row.getOrigin(), + ""Rotation"": row.getOrient(), + ""Direction"": row.getDirection(), + ""Spacing"": row.getSpacing() + } + + # Store site of the row in the row_site_dict + row_site_dict[row.getName()] = row.getSite() + +# Iterate through each net +for net in nets: + # Map net name to its wire + net_wire_dict[net.getName()] = net.getWire() + +# Return a tuple containing row information, row sites, and net wire mappings +return (row_info_dict, row_site_dict, net_wire_dict)","Get the location, rotation, direction, and spacing of rows as a dictionary with row index as key and get the sites of rows, followed by a dictionary with nets as keys and their wires as values." +"# Get the tapcell and reset it +tap_cell = design.getTapcell() +tap_cell.reset() + +# Get the current block of the design +block = design.getBlock() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Set the placement status of the instance to 'UNPLACED' +inst.setPlacementStatus('UNPLACED') + +# Retrieve the capacitor-coupled segments +cc_segs = block.getCCSegs() + +# Return the coupling capacitance segments +return cc_segs","reset the tapcell, set the placement Status of the instance '_411_' to 'UNPLACED' and retrieve the capacitor-coupled segments of the bock" +"# Get the tapcell in the design and reset it +tap_cell = design.getTapcell() +tap_cell.reset() + +# Get the current block of the design +block = design.getBlock() + +# Return all blockages +return block.getBlockages()",Get all the blockages and reset the tapcell in the design. +"# Get the current block of the design +block = design.getBlock() + +# Find the instance '_411_' and 'input1' +inst1 = block.findInst('_411_') +inst2 = block.findInst('input1') + +# Mark the first output nets of the instances '_411_' and 'input1' +inst1.getFirstOutput().getNet().setMark(True) +inst2.getFirstOutput().getNet().setMark(True) + +# Get the placement bounding box of the master cell of the instance '_411_' +placement_boundary = inst1.getMaster().getPlacementBoundary() + +# Extract coordinates of the placement bounding box +coordinates = { + ""ul"": placement_boundary.ul(), + ""ll"": placement_boundary.ll(), + ""lr"": placement_boundary.lr(), + ""ur"": placement_boundary.ur() +} + +# Return the coordinates +return coordinates","Mark the first output nets of the instances '_411_' and 'input1' and get the ul, ll, lr, ur coordinates of the placement bounding box of the master cell of the instance '_411_'." +"# Get the current block of the design +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Define the direction for the layers +direction = 'HORIZONTAL' + +# List to store horizontal tech layers and their capacitance +horizontal_layers = [] + +# List to store instances whose masters are not of type CORE +non_core_master_insts = [] + +# Iterate through each instance +for inst in insts: + # Check if the master cell of the instance is not of type CORE + if not inst.getMaster().isCore(): + # Append the instance to the list of non-core master instances + non_core_master_insts.append(inst) + +# Iterate through each layer in the technology +for layer in layers: + # Check if the layer direction is HORIZONTAL + if layer.getDirection() == direction: + # Append the layer and its capacitance to the list of horizontal layers + horizontal_layers.append((layer, layer.getCapacitance())) + +# Reset the tapcell +tap_cell = design.getTapcell() +tap_cell.reset() + +# Return a tuple containing non-core master instances and horizontal layers +return (non_core_master_insts, horizontal_layers)","Get the instances whose masters are not of type CORE and get the horizontal tech layers and their capacitance, followed by resetting the tapcell" +"# Get the layersthat are set as RectOnly +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a list to store layers that are set as RectOnly +rect_layers_alias = [] + +# Iterate through all layers +for layer in layers: + # Check if the layer is set as RectOnly + if layer.isRectOnly(): + # Append the rectangle-only layer Aliases to the list + rect_layers_alias.append(layer.getAlias()) + +# Return the list of rectangle-only layers +return rect_layers_alias",Get the layers that are set as RectOnly and get their alias. +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Dictionary to store resistance of all layers +layer_resistance = {} + +# Iterate through each layer to retrieve resistance +for layer in layers: + layer_resistance[layer.getName()] = layer.getResistance() + +# Dictionary to store edge capacitance of all layers +layer_edge_capacitance = {} + +# Iterate through each layer to retrieve edge capacitance +for layer in layers: + layer_edge_capacitance[layer.getName()] = layer.getEdgeCapacitance() + +# Combine resistance and edge capacitance dictionaries into a single result dictionary +result = { + ""edge_capacitance"": layer_edge_capacitance, + ""layer_resistance"": layer_resistance +} + +# Return the result dictionary +return result +",Get the resistance and edge capacitance of all the layers +"# Get the current block of the design +block = design.getBlock() + +# Find the port named 'req_val' +port = block.findBTerm('req_val') + +# Disconnect the port from the nets it is connected to +port.disconnect() + +# Set the port named 'req_val' to special +port.setSpecial() + +# Get the logic ports +logic_ports = block.getLogicPorts() + +# Return the logic ports +return logic_ports","Disconnect the port named 'req_val' from the nets it is connected to and set the port named 'req_val' to special, and return the logic ports" +"# Get the current block of the design +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Get the wire_updated nets +updated_nets = block.getWireUpdatedNets(nets) + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# List to store horizontal layers in the technology file +horizontal_layers = [] + +# Iterate through each layer in the technology +for layer in layers: + # Check if the layer direction is HORIZONTAL + if layer.getDirection() == 'HORIZONTAL': + # Append the horizontal layer to the list + horizontal_layers.append(layer) + +# Create a dictionary containing updated nets and horizontal layers +result = { + ""nets"": updated_nets, + ""layers"": horizontal_layers +} + +# Return the result dictionary +return result",Get all the wire_updated nets and get the horizontal layers +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the count of layers +layer_count = tech.getLayerCount() + +# Get the Routing Layer Count +routing_layer_count = tech.getRoutingLayerCount() + +# Get the logic ports +logic_ports = block.getLogicPorts() + +# Create a dictionary containing layer count, routing layer count, and logic ports +result = { + ""layer_count"": layer_count, + ""routing_layer_count"": routing_layer_count, + ""logic_ports"": logic_ports +} + +# Return the result dictionary +return result","Get the count of layers and get the routing layer count, along with the logic ports" +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the count of Manufacturing Grid +mfg = tech.getManufacturingGrid() + +# Find the net with name ""req_msg[13]"" +net = block.findNet(""req_msg[13]"") + +# Set the Capacitance Coupling Adjust Order of the net to 1 +net.setCcAdjustOrder(1) + +# Return the count of Manufacturing Grid +return mfg","Get the count of manufacturing grid and set the capacitance Coupling Adjust Order of the net with name ""req_msg[13]"" to 1." +"# Get the current block of the design +block = design.getBlock() + +# Find the net with name ""req_msg[11]"" +net1 = block.findNet(""req_msg[11]"") +# Set the Capacitance Coupling Adjust Factor to 1 +net1.setCcAdjustFactor(1) + +# Find the net with name ""req_msg[12]"" +net2 = block.findNet(""req_msg[12]"") +# Set the Capacitance Coupling Calibration Factor to 2 +net2.setCcCalibFactor(2)","Set the Capacitance Coupling Adjust Factor of the net with name ""req_msg[11]"" to 1 and set the Capacitance Coupling Calib Factor of the net with name ""req_msg[12]"" to 2." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all nets present in the design block +nets = block.getNets() +result = [] +# Iterate over each net in the design block +for net in nets: + # Check the signal type of the net + if net.getSigType() != 'POWER' and net.getSigType() != 'GROUND': + # Get the name of the net + net_name = net.getName() + # Get the total Capacitance of the net + net_cap = net.getTotalCapacitance() + # Get the total resistance of the net + net_res = net.getTotalResistance() + # Get the total coupling capacitance of the net + net_coupling = net.getTotalCouplingCap() + # Append the net name, net capacitance, net resistance and net coupling + result.append([net_name,net_cap,net_res,net_coupling]) +return result","Get the total capacitance, total resistance, Coupling Capacitance of all the nets except the nets that are connected to Ground and Power External Power Supply. Get them as list of lists, in which each list contains the net name, net capacitance, net resistance and net coupling." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the pins (which are also called Iterms in OpenROAD) +pins = block.getITerms() +result = [] +#Iterate through all the pins +for pin in pins: + # Check if the pin is in clock + if design.isInClock(pin.getInst()): + # Append the pin to the result + result.append(pin) +return result",Get all the Pins which are in clock net as a list. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input1"" as mentioned in the prompt +inst = block.findInst(""input1"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the X Minimum of the Bounding Box of the instance +xmin = BBox.xMin() +# Get the Y Minimum of the Bounding Box of the instance +ymin = BBox.yMin() +# Get the X Maximum of the Bounding Box of the instance +xmax = BBox.xMax() +# Get the Y Maximum of the Bounding Box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Get the Bounding Box of an instance named ""input1"". Return a list of coordinates (Xmin, Ymin in one list and Xmax, Ymax in next list) " +"# Get all the libraries in the database +libs = db.getLibs() +d = {} +# Iterate through all the libraries files +for lib in libs: + # Get the library cells of the library + masterCells = lib.getMasters() + cells = [] + # Iterate through all the library cells + for master in masterCells: + # Append the library cell to the cells + cells.append(master) + d[lib.getName()] = cells +return d",Get all the library cells as a dictionary of list. Key of the dictionary is library name and the value is the list of all the library cells in the library file +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all nets present in the design block +nets = block.getNets() +result = [] +# Iterate over each net in the design block +for net in nets: + # Get the Pins of the net + pins = net.getITerms() + # Check if the length of number of pins of net is Zero + if len(pins)==0: + # Append the net to the result + result.append(net) +return result",Get all the nets which are not connected to any pins and return them as list. +"# Get OpenDB +db = ord.get_db() +# Get all read libraries +libs = db.getLibs() +# Create a list to store the names +libcell_name_list = [] +# Iterate through all libraries +for lib in libs: + # Get all library cells in this library file + lib_masters = lib.getMasters() + # Iterate through all library cells + for master in lib_masters: + # Get the name of the library cell + libcell_name = master.getName() + # Add the name to the list + libcell_name_list.append(libcell_name) +return libcell_name_list",Get the name of every liberty cell +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +orientation = [] +# Retrieve all instances present in the design block +insts = block.getInsts() +# Iterate over each instance in the design block +for inst in insts: + # Append the get rotation of the instance + orientation.append([inst.getName(), inst.getOrient()]) +return orientation",Get the rotations of all instances as a list of lists +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst('input1') +# Set the rotation of the instance as ""MX"" +inst.setOrient('MX')",Set the rotation of an instance 'input1' as 'MX' +"# Get the current block from the design +block = design.getBlock() + +# Retrieve the instance ""output53"" within the design +inst = block.findInst('output53') + +# Initialize a list to store the net of the output pin +output_nets = [] + +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Check if the pin represents as an output signal + if pin.isOutputSignal(): + # Retrieve the net associated with this output pin + net = pin.getNet() + # If net is not None then append it to the output_net + if net: + output_nets.append(net) + +# Return the net connected to the output pin of the specified instance +return output_nets",get the nets of the output pins of the instance 'output53' +"# Get the width and height of the bounding box of instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Get the Bounding Box +bounding_box = inst.getBBox() + +# Get the DX and DY of the Bounding Box of the instance +return (bounding_box.getDX(), bounding_box.getDY())",Get the width and height of the bounding box of instance '_411_' +"# Set the level of all 'AND2_X1' gate instances in the design to 1 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through all instances +for inst in insts: + # Check if the instance's master name contains 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Set the level of the instance to 1 + inst.setLevel(1, False)",set the level of all 'AND2_X1' gate instance in the design to 1 +"# Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store the coordinates of the lower-left corner of the bounding box of the instances +inst_to_master_transform_offset = {} + +# Iterate through all instances +for inst in insts: + + # Check if the name of the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Add the instance name and the coordinates of the lower-left corner of the bounding box to the dictionary + inst_to_master_transform_offset[inst.getName()] = inst.getTransform().getOffset() + +# Return the dictionary containing the coordinates of the lower-left corner of the bounding box of the instances +return inst_to_master_transform_offset",Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' +"# Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store the coordinates of the lower-left corner of the bounding box of the instances +inst_to_master_transform_offset = {} + +# Iterate through all instances +for inst in insts: + + # Check if the name of the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Add the instance name and the coordinates of the lower-left corner of the bounding box to the dictionary + inst_to_master_transform_offset[inst.getName()] = inst.getOrigin() + +# Return the dictionary containing the coordinates of the lower-left corner of the bounding box of the instances +return inst_to_master_transform_offset",Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' +"# Retrieve the orientation of instances that have 'AND2_X1' as their library cell type. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store the orientation of instances +inst_to_master_transform_orient = {} + +# Iterate through all instances +for inst in insts: + # Check if the master name is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Add the instance name and its rotation to the dictionary + inst_to_master_transform_orient[inst.getName()] = inst.getTransform().getOrient() + +# Return the dictionary containing the orientation of instances +return inst_to_master_transform_orient",Retrieve the rotation of instances that have 'AND2_X1' as their library cell type. +"# Retrieve the orientation of instances that have 'AND2_X1' as their library cell type. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store the orientation of instances +inst_to_master_transform_orient = {} + +# Iterate through all instances +for inst in insts: + # Check if the master name is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Add the instance name and its rotation to the dictionary + inst_to_master_transform_orient[inst.getName()] = inst.getOrient() + +# Return the dictionary containing the orientation of instances +return inst_to_master_transform_orient",Retrieve the rotation of instances that have 'AND2_X1' as their library cell type. +"# Get the first output pin of an instance and map it to the instance names as the value in the dictionary. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store instances and their output pins +inst_outputs = {} + +# Iterate through all instances +for inst in insts: + # Add the instance name and its first output pin to the dictionary + inst_outputs[inst.getName()] = inst.getFirstOutput() + +# Return the dictionary containing instances and their output pins +return inst_outputs",Get the first output pin of an instance and map it to the instance names as the value in the dictionary. +"# Set the user-defined flags 1and 3 to true for instance '_411_' and return the instance + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Set the user-defined flags 1 and 3 to true +inst.setUserFlag1() +inst.setUserFlag3() + +# Return the modified instance +return inst",Set the user-defined flags 1and 3 to true for instance '_411_' and return the instance +"# Get the ul, ll, lr, ur coordinates of the placement bounding box of the master cell of the instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the master cell associated with the instance +master = inst.getMaster() + +# Get the placement bounding box of the master cell +placement_boundary = master.getPlacementBoundary() + +# Get the coordinates of the placement bounding box + +# Upper Left placement bounding box +ul = placement_boundary.ul() + +# Lower Left Left placement bounding box +ll = placement_boundary.ll() + +# Lower Right placement bounding box +lr = placement_boundary.lr() + +# Upper Right placement bounding box +ur = placement_boundary.ur() + +# Return the coordinates +coordinates = [ul, ur, lr, ll] +return coordinates","get the upper left, upper right, lower left, lower right coordinates of the placement bounding box of the master cell of the instance '_411_'" +"# Get the current block of the design +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Check if instance '_411_' is type ENDCAP or any of its subtypes +inst_is_endcap = inst.isEndCap() + +# Clear user-defined flags of instance '_411_' +inst.clearUserFlag1() +inst.clearUserFlag2() +inst.clearUserFlag3() + +# List to store instances having hierarchy and whose library cell name is ""AND2X_1"" and on level 1 +inst_list = [] + +# Iterate through each instance +for inst in insts: + # Check if the instance is hierarchical, its library cell name is ""AND2X_1"", and is level 1 + if inst.isHierarchical() and inst.getMaster().getName() == ""AND2X_1"" >= 0 and inst.getLevel() == 1: + # Append the instance to the list + inst_list.append(inst) + +# Return a tuple containing the status of the instance '_411_' to determine if it is of type ENDCAP or any of its subtypes, along with a list of instances that have a hierarchy. +return (inst_is_endcap, inst_list) +","Check if the instance '_411_' is type ENDCAP or any of its subtypes, and clear user-defined flags of instance '_411_', then get all the instances with hierarchicy and whose library cell is AND2X_1 and the instance is level 1." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst('input1') +# Get the corresponding design block of the instance +return inst.getBlock()","Given the instance name 'input1', get the design block this instance belongs to." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the DB units per micron +return block.getDbUnitsPerMicron()",Convert 1 um to units used in this technology in OpenROAD +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the DEF units of this technology +return block.getDefUnits()",Get the DEF units of this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the db rows +rows = block.getRows() +d = {} +# Iterate through all the rows +for row in rows: + # Get the name of the db row + name = row.getName() + # Get the spacing of the db row + spacing = row.getSpacing() + d[row] = [name, spacing] +return d","Get the rows with its name and spacing in a form of a dictionary. The key of the dictionary is the row object, the value is a list containing name and spacing of the row object" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the unit used in def file to 3000 as mentioned in the prompt +block.setDefUnits(3000)",Set the def units per micron to 3000 +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the modules +modules = block.getModules() +module_names = [] +# Iterate through all the modules +for module in modules: + # Append the names of the module + module_names.append(module.getName()) +return module_names",Get all the modules and return the names of modules as a list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst(""inpu1"") +inst.setUserFlag1()","Set user-defined flag 1 to ture on the instance with name ""input1""" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +adjust_factor = [] +# Iterate through all the nets +for net in nets(): + # Append the capacitance coupling adjust factor of the net + adjust_factor.append(net.getCcAdjustFactor()) +return adjust_factor",Get the capacitance coupling Adjust Factor of every net and return them as a list. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +adjust_order = [] +# Iterate throgh all the nets +for net in nets(): + # Append the capacitance coupling adjust order of the net + adjust_order.append(net.getCcAdjustOrder()) +return adjust_order",Get the capacitance coupling Adjust Order of every net and return them as a list. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +track_list = [] +# Iterate throgh all the nets +for net in nets: + # Get the tracks of the net + tracks = net.getTracks() + # Append the tracks to the track list + track_list.append(tracks) +return track_list",Get the tracks of every net as a list of lists. Each list in the output list should contain the tracks of respective net +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst(""input1"") +# Get the nets of the instance +nets = inst.getNets() +track_list = [] +# Iterate through all the nets +for net in nets: + # Get the tracks of the net + tracks = net.getTracks() + track_list.append(tracks) +return track_list","Get the tracks of nets that are connected to instance with name ""input1"" as a list of list. Each list in the output list should contain the tracks of respective net" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the nets +nets = block.getNets() +types = [] +# Iterate through all the nets +for net in nets: + # Append the wire type of the net + types.append(net.getWireType()) +return types",Get the wire type of each net and return them as a list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the nets +nets = block.getNets() +termsCount = [] +# Iterate through all the nets +for net in nets: + # Get term counts of the net and append to the array + termsCount.append(net.getTermCount()) +return termsCount",Get term count of every net and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +insts = block.getInsts() +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rise arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than 0.5 second as mentioned in the prompt + if pin_rise_arr > 0.5: + output.append(pin) +return output",Get all the pins which has the rising arrival time greater than 0.5 sec and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +insts = block.getInsts() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is less than or equal 0.5 second as mentioned in the prompt + if pin_rise_arr <= 0.5: + output.append(pin) + +return output",Get all the pins which has the rising arrival time less than or equal to 0.5 second and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +insts = block.getInsts() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the fall arrival time is greater than 0.8 second as mentioned in the prompt + if pin_fall_arr > 0.8: + # Append the pin to the output + output.append(pin) + +return output",Get all the pins which has Pin Fall Arrival Time greater than 0.8 sec and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +# Iterate through all the nets +for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + return True +return False",Check all the nets and check if any of its wires is replaced with a new wire. Return True if Altered and false otherwise +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +# Iterate through all the ports +for port in ports: + # Append the name and net of the port in the dictionary + d[port.getName()] = port.getNet() +return d",Get all the net of ports and return a dictionay with port name as key and Net of the port as Value of the dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +# Iterate through all the ports +for port in ports: + # Append the name and block pins objects of the port in the dictionary + d[port.getName()] = port.getBPins() +return d",Get all the design block pins objects of ports and return a dictionay with port name as key and pins of the port as Value of the dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the design block ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +placement_status_with_name = {} +# Iterate through all the ports +for port in ports: + # Get the name of the port + name = port.getName() + # Get the placement status of the port + status = port.getFirstPinPlacementStatus() + # Append the placement status and name of the port to the dictionary + placement_status_with_name[name] = status +return placement_status_with_name",Get the name of every design block port with the placement status of the first pin as a dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +output = [] +# Iterate through all the ports +for port in ports: + # Append the port name and signal type of the port to the dictionary + d[port.getName()] = port.getSigType() +return d",Get the name of every block port with its signal type as a dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +output = [] +# Iterate through all the ports +for port in ports: + # Append the port name and IO type of the port to the dictionary + d[port.getName()] = port.getIoType() +return d",Get all the I/O types of ports and return a dictionay with port name as keys and IO Type of the port as values +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm(""req_val"") +# Find the boundary box of the port +BBox = port.getBBox() +# Get the X Min of the bounding box +xmin = BBox.xMin() +# Get the Y Min of the bounding box +ymin = BBox.yMin() +# Get the X Max of the bounding box +xmax = BBox.xMax() +# Get the Y Max of the bounding box +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Get the Bounding Box of a port named ""req_val"". Return a list of coordinates (Xmin, Ymin in one list and Xmax, Ymax in another list) " +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Set SPECIAL attribute to the port +port.setSpecial()",Set SPECIAL attribute port named 'req_val' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Return whether the port has SPECIAL +return port.isSpecial()",Check if the port named 'req_val' has SPECIAL attribute +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +# get and report wire_updated nets +return block.getWireUpdatedNets(nets)",Get the of nets for any wire changes and report the statistics of the nets with changed wires. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the technology layers +return tech.getLayers()",Get the technolgy layers. The layers are ordered from the bottom mask number to the top mask number. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the number of layers in this technology. +return tech.getLayerCount()",Get the number of layers in this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the number of routing-layers in this technology. +return tech.getRoutingLayerCount()",Get the number of routing-layers in this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the number of vias in this technolgy. +return tech.getViaCount()",Get the number of vias in this technolgy. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the via generate rules in this technolgy +return tech.getViaGenerateRules()",Get the via generate rules in this technolgy. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get the technolgy vias. This includes non-default-rule-vias. +return tech.getVias()",Get the technolgy vias +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get LEF CLEARANCEMEASURE +return tech.getClearanceMeasure()",Get LEF CLEARANCEMEASURE +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return MANUFACTURINGGRID +# NOTE: Assumes conversion to internal DB units, +# NOT microns or LEF/DEF units +return tech.getManufacturingGrid()",Get MANUFACTURINGGRID +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the net with name ""req_msg[11]"" +net = block.findNet(""req_msg[11]"") +# Set the capacitance coupling adjust factor of the net to 1 +net.setCcAdjustFactor(1)","Set the capacitance coupling adjust factor of the net with name ""req_msg[11]"" to 1" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the net with name ""req_msg[11]"" +net = block.findNet(""req_msg[11]"") +# Set the capacitance coupling calibration factor of the net to 2 +net.setCcCalibFactor(2)","Set the capacitance coupling calibration factor of the net with name ""req_msg[11]"" to 2" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +output = {} +# Iterate through all the nets +for net in nets: + # Append the net name and capacitance coupling match ratio against the net to a dictionary + output[net.getName()] = net.getCcMatchRatio() +return output",Get the capacitance coupling match ratio against this nets with the name of the net. Return a dictionary with key being the name of the net and value of the dictionary is the capacitance coupling match ratio against the net +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Iterate through the net names ""req_msg[13] and ""clk"" as mentioned in the prompt +for net_name in [""req_msg[13]"", ""clk""]: + # Find the net with net name as parameter + net = block.findNet(net_name) + # Set the coupling capacitance match ratio against the net to 1 + net.setCcMatchRatio(1)","Set the coupling capacitance match ratio against the net with name ""req_msg[13]"" and ""clk"" to 1" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get the technology layers +layers = tech.getLayers() +output = [] +# Iterate through all the layers +for layer in layers: + # Get the names of the technology layers + output.append(layer.getName()) +return output",Get the names of the technology layers +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get all the tehnology layers +layers = tech.getLayers() +output = {} +# Iterate through all the technology layers +for layer in layers: + # Append the layer name and AREA parameter to the dictionary + output[layer.getName()] = layer.getArea() +return output",Get the AREA parameter of the technology layers with their name. Return a dictionary with key as the layer name and value as the AREA parameter +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get all the technology layers +layers = tech.getLayers() +output = {} +# Iterate through all the layers +for layer in layers: + # Append the layer name and layer direction to the dictionary + output[layer.getName()] = layer.getDirection() +return output",Get the directions of the technology layers with their name. Return a dictionary with key as the layer name and value as the layer direction +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name 'metal8' +layer = tech.findLayer('metal8') +# Return the routing layer corner spacing rule +return layer.getTechLayerCornerSpacingRules()",Get the routing layer corner spacing rules of technology layer with name 'metal8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name 'metal8' +layer = tech.findLayer('metal8') +# Return the cut layer class rule +return layer.getTechLayerCutClassRules()",Get the cut layer class rule of layer with name 'metal8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name 'metal8' +layer = tech.findLayer('metal8') +# Get the cut layer spacing rules +return layer.getTechLayerCutSpacingRules()",Get the cut layer spacing rules of layer with name 'metal8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal10"" +layer = tech.findLayer('metal10') +# Return the end of line extension rules +return layer.getTechLayerEolExtensionRules()",Get the end of line extension rules of the technology layer with name 'metal10' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology object with technology information +tech = block.getTech() +# Find the layer with name ""via8"" +layer = tech.findLayer('via8') +# Return the tech layer forbidden spacing rules +return layer.getTechLayerForbiddenSpacingRules()",Get the forbidden spacing rules of the technology layer with name 'via8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""via1"" +layer = tech.findLayer('via1') +# Return the keepout zone rules +return layer.getTechLayerKeepOutZoneRules()",Get the keepout zone rules of the technology layer with name 'via1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer called ""OVERLAP"" +layer = tech.findLayer('OVERLAP') +# Return two widths spacing rules +# API for version 5.7 two widths spacing rules, expressed as a 2D matrix +# with index tables +return layer.getTwoWidthsSpacingTableNumWidths()",Get the two widths spacing rules of the technology layer with name 'OVERLAP' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name ""metal1"" +layer = tech.findLayer('metal1') +# Return the min cut rules +return layer.getTechLayerMinCutRules()",Get the minimum cut rules of the technology layer with name 'metal1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name ""via2"" +layer = tech.findLayer('via2') +# Return the minimum step rules +return layer.getTechLayerMinStepRules()",Get the minimum step rules of the technology layer with name 'via2' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the collection of spacing rules for the object, assuming +# coding in LEF 5.4 format. +return layer.getV54SpacingRules()",Get the collection of spacing rules for the layer with name 'metal3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal4"" +layer = tech.findLayer('metal4') +# Return the spacing end of line rules +return layer.getTechLayerSpacingEolRules()",Get the spacing end of line rules of layer with name 'metal4' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal5"" +layer = tech.findLayer('metal5') +# Return the layer type +return layer.getType()",Get the type of technology layer with name 'metal5' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""via3"" +layer = tech.findLayer('via3') +# Return the wrong direction spacing rules +return layer.getTechLayerWrongDirSpacingRules()",Get the wrong direction spacing rules of layer with name 'via3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal1"" +layer = tech.findLayer('metal1') +# Return the x-axis offset +return layer.getOffset()",Get the offset along the x-axis of the technology layer with name 'metal1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal2"" +layer = tech.findLayer('metal2') +# Return the x-axis offset +return layer.getOffsetX()",Get the offset along the x-axis of the technology layer with name 'metal2' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the y-axis offset +return layer.getOffsetY()",Get the offset along the y-axis of the technology layer with name 'metal3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the y-axis offset +layer.setOffsetXY(0.2, 0.15)",Change the offset setting along the x-axis to 0.2 microns and the y-axis to 0.15 microns for the technology layer named 'metal3'. +"# Retrieve block information +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Get the technology information +tech = block.getTech() + +# Initialize a dictionary to store instance halos +inst_halos = {} + +# Iterate through each instance +for inst in insts: + # Store the halo information for each instance + inst_halos[inst.getName()] = inst.getHalo() + +# Find layer information for 'metal4' +layer1 = tech.findLayer('metal4') + +# Get technology layer spacing End-of-Line (EOL) rules for 'metal4' +layer_spacing_eol_rules = layer1.getTechLayerSpacingEolRules() + +# Find layer information for 'metal8' +layer2 = tech.findLayer('metal8') + +# Get technology layer corner spacing rules for 'metal8' +layer2_corner_spacing_rules = layer2.getTechLayerCornerSpacingRules() + +# Find layer information for 'metal5' +layer3 = tech.findLayer('metal5') + +# Get technology layer cut class rules for 'metal5' +layer_cut_class_rules = layer3.getTechLayerCutClassRules() + +# Store all the collected information in a dictionary +result = { + ""halos"": inst_halos, + ""metal4_EOL"": layer_spacing_eol_rules, + ""metal8_corner_spacing_rules"": layer2_corner_spacing_rules, + ""cut_class_rules"": layer_cut_class_rules +} + +# Return the collected information +return result","Get the following in a dictionary, with the given key names: +1. get all the halos of the instances with inst name as key. the key should be halos. +2. Get the routing layers spacing EOL rules of layer with name 'metal4'. The key should be metal4_EOL. +3. Get the routing layers corner spacing rules of layer with name 'metal8'. The key should be metal8_corner_spacing_rules. +4. get the routing layers cut class rules of layer with name 'metal8'. The key name for this will be cut_class_rules." +"# Get the current design block +block = design.getBlock() + +# Retrieve the capacitor-coupled segments +cc_segments = block.getCCSegs() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store source type of instances on level 1 whose master cells are either NAND or NOR +src_type = {} + +# Iterate through each instance +for inst in insts: + # Get the library cell of the instance + master = inst.getMaster() + + # Check if the library cell is special power type + if master.isSpecialPower(): + # Set the master of the instance as frozen so dbMTerms cannot be added or delete from the master once it is frozen. + inst.getMaster().setFrozen(True) + + # Check if the name of library cell is ""NAND2_X1"" or ""NOR3_X1"" and the instance is on level 1 + if (master.getName() == ""NAND2_X1"" or master.getName() == ""NOR3_X1"") and inst.getLevel() == 1: + # Store the source type of the instance in the dictionary + src_type[inst.getName()] = inst.getSourceType() + +# Return the tuple containing the cc_segments and the source type dictionary of instances +return (cc_segments, src_type)","Retrieve the capacitor-coupled segments and frozen the library cells with special power type, then get source type of all the instances on level 1 whose master cells are either ""NAND2_X1"" or ""NOR3_X1""." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Find the instance '_411_' +inst1 = block.findInst('_411_') + +# Set user-defined flags 1 and 3 for instance '_411_' +inst1.setUserFlag1() +inst1.setUserFlag3() + +# Find the instance 'input1' +inst2 = block.findInst('input1') + +# Mark the first output nets of the instances '_411_' and 'input1' +net1 = inst1.getFirstOutput().getNet() + +# Dictionary to store instance transform offsets +inst_transform_offset_dict = {} + +# Iterate through each instance +for inst in insts: + # Check if the master cell name is ""AND2X_1"" + if inst.getMaster().getName() == ""AND2X_1"": + # Store the offset of the instance with master 'AND2_X1' + inst_transform_offset_dict[inst.getName()] = inst.getTransform().getOffset() + +# Return the dictionary containing instance transform offsets +return inst_transform_offset_dict","Set user-defined flags 1 and 3 for instance '_411_' and mark the first output nets of the instances '_411_' and 'input1', followed by getting the offset of the instances whose master is 'AND2_X1' in the form of dictionary with instance name as key." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store instances and their respective regions +inst_regions = {} + +# List to store pad instances on level 0 +inst_list = [] + +# Iterate through each instance +for inst in insts: + # Store instance name and its region in the inst_regions dictionary + inst_regions[inst.getName()] = inst.getRegion() + + # Check if the instance is a pad and it's on level 0 + if inst.isPad() and inst.getLevel() == 0: + # Append the instance to the list of pad instances + inst_list.append(inst) + + # Check if the instance name is ""input1"" + if inst.getName() == ""input1"": + # Iterate through each pin of the instance + for pin in inst.getITerms(): + # Get the net connected to the pin + net = pin.getNet() + # Check if the net exists + if net: + # Set RC disconnected for the net + net.setRCDisconnected(True) + +# Return the list of pad instances +return inst_list",Retrieve the instances and their corresponding areas if they are PAD or any of its subtypes and set as level 0. Proceed to disconnect the RC for the networks associated with the 'input1' instance. +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store offsets of instances whose master cell is 'NAND2_X1' +NAND_offsets = {} + +# Iterate through each instance +for inst in insts: + # Check if the library cell name is ""NAND2_X1"" + if inst.getMaster().getName() == ""NAND2_X1"": + # Store the xy location of the instance + NAND_offsets[inst.getName()] = inst.getTransform().getOffset() + + # Check if the instance name is ""_411_"" + if inst.getName() == ""_411_"": + # Iterate through each pin of the instance + for pin in inst.getITerms(): + # Get the net connected to the pin + net = pin.getNet() + # Check if the net exists + if net: + # Set RC disconnected for the net + net.setRCDisconnected(True) + +# Return the dictionary containing offsets of instances +return NAND_offsets",Get the offset of all 'NAND2_X1' cells and set the RC disconnected for the nets of the instance 'input1'. +"block = design.getBlock() + +# find the instance 'output53' +inst = block.findInst('output53') + +# Initialize a list to store the input pins of the instance +input_pins = [] + + +# Obtain all pins associated with this instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Check if the pin represents an input signal + if pin.isInputSignal() and pin: + # Append the input pin to the list of input pins + input_pins.append(pin) + +# Return the list of input pins connected to the instance +return input_pins",get the input pins of the instance 'output53' +"# Get the nets of the input pins of instance 'output53' + +block = design.getBlock() + +# find the instance 'output53' +inst = block.findInst('output53') + +# Initialize a list to store nets of input pins +input_nets = [] + +# Get all input pins (ITerms) of the instance +pins = inst.getITerms() + +# Iterate through all input pins +for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal() and pin: + # If it's an input signal, add its net to the list + input_nets.append(pin.getNet()) + +# Return the list of nets of input pins of the instance +return input_nets",get the nets connected to the input pins of the instance 'output53' +"# Retrieve all instances that have a hierarchy and whose library cell type is 'AND2_X1' and are on level 1. + +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store matching instances +inst_list = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance has hierarchy, its library cell is 'AND2_X1', and it is on level 1 + if inst.isHierarchical() and inst.getMaster().getName()==""AND2_X1"" and inst.getLevel() == 1: + # Add the instance to the list + inst_list.append(inst) + +# Return the list of matching instances +return inst_list +",Retrieve all instances that have a hierarchy and whose library cell type is 'AND2_X1' and are on level 1. +"# Get the resistor segments + +# Get the design block +block = design.getBlock() + +# Return the resistor segments +return block.getRSegs()",get the resistor segments of the design block +"# Retrieve the LEQ (Logical equivalent) information associated with the library cell of instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the library cell associated with the instance +master = inst.getMaster() + +# Retrieve the LEQ information +leq_info = master.getLEQ() + +# Return the LEQ information +return leq_info",Retrieves the LEQ (Logical equivalent) information associated with the library cell of instance '_411_' +"# Get all the pad and set as level 1 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store matching instances +inst_list = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance is a pad and it is level 1 + if inst.isPad() and inst.getLevel() == 1: + # Add the instance to the list + inst_list.append(inst) + +# Return the list of matching instances +return inst_list",get all the pad instances that are level 1 +"# Get the vertical thickness multiplier for the IO pin placer's parameters and set corner avoidance to 50 + +# Get the IO pin placer +iop = design.getIOPlacer() + +# Get the parameters of the IO pin placer +parameters = iop.getParameters() + +# Set corner avoidance to 50 +parameters.setCornerAvoidance(50) + +# Return the vertical thickness multiplier +return parameters.getVerticalThicknessMultiplier()",get the vertical thickness multiplier for the IO pin placer's parameters and set corner avoidance to 50 +"# Get the design block +block = design.getBlock() + +# Find the instance named ""FILLER_0_17_159"" +inst = block.findInst(""FILLER_0_17_159"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Reverse the resistor segment sequence of the net + net.reverseRSegs() +",Reverse the resistor segment seqence of the nets of the instance FILLER_0_17_159 +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets with wire-ordered flag set as True +ordered_wires = [] + +# Iterate through each net +for net in nets: + # Check if the wire-ordered flag is set to true + if net.isWireOrdered(): + # Append the net to the list + ordered_wires.append(net) + +# Return the list of nets with ordered wires +return ordered_wires +","Get the nets if their wire-ordered flag is set as True, and return it as a list" +"# Get the design block +block = design.getBlock() + +# List of net names to set wire type as ROUTED +nets = [ + ""_000_"", + ""_001_"", + ""_002_"", + ""_003_"", + ""_004_"", + ""_005_"", + ""_006_"", + ""_007_"", + ""_008_"", + ""_009_"", + ""_010_"" +] + +# Iterate through each net name +for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire type of the net as ROUTED + net.setWireType('ROUTED') + + +","Set the following nets wire type to ROUTED: _000_, _001_, _002_, _003_, _004_, _005_, _006_, _007_, _008_, _009_, _010_ +" +"# Get the design block +block = design.getBlock() + +# List to store nets with ordered wires +ordered_wires = [] + +# List of net names +nets = [ + ""net1"", + ""net10"", + ""net11"", + ""net12"", + ""net13"", + ""net14"", + ""net15"", + ""net16"", + ""net17"", + ""net18"", + ""net19"" +] + +# Iterate through each net name +for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire ordered flag to true + net.setWireOrdered(True) + + # Append the net to the list of nets with ordered wires + ordered_wires.append(net) + +# Return the list of nets with ordered wires +return ordered_wires +","Set the wires ordered flag to true for the following nets and return a list of these nets: net1, net10, net11, net12, net13, net14, net15, net16, net17, net18, net19 +" +"# Get the design block +block = design.getBlock() + +# List to store nets +altered_wires_net = [] + +# List of net names +nets = [ + ""_000_"", + ""_001_"", + ""_002_"", + ""_003_"", + ""_004_"", + ""_005_"", + ""_006_"", + ""_007_"", + ""_008_"", + ""_009_"", + ""_010_"" +] + +# Iterate through each net name +for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire update flag to true + net.setWireAltered(True) + + # Append the net to the list of nets + altered_wires_net.append(net) + +# Return the list of the nets +return altered_wires_net +","Set the wire update flag to true for the wires of the following nets and return a list of these nets: _000_, _001_, _002_, _003_, _004_, _005_, _006_, _007_, _008_, _009_, _010_ +" +"# Get the design block +block = design.getBlock() + +# List to store selected nets +selected_nets = [] + +# List of net names to select +net_names = [ + ""net1"", + ""net10"", + ""net11"", + ""net12"", + ""net13"", + ""net14"", + ""net15"", + ""net16"", + ""net17"", + ""net18"", + ""net19"" +] + +# Iterate through each net name +for name in net_names: + # Find the net object by name + net = block.findNet(name) + + # Set the net as selected + net.setSelect(True) + + # Append the selected net to the list + selected_nets.append(net) + +# Return the list of selected nets +return selected_nets +","set the select flag true for the following nets and return the list of these nets: net1, net10, net11, net12, net13, net14, net15, net16, net17, net18, net19 +" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets +wild_connected_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is connected using a wild-card + if net.isWildConnected(): + # Append the net to the list + wild_connected_nets.append(net) + +# Return the list of nets +return wild_connected_nets +",Get the nets connected using a wild-card. +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets marked as ""do not touch"" +do_not_touch_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is set as ""do not touch"" + if net.isDoNotTouch(): + # Append the net to the list + do_not_touch_nets.append(net) + +# Return the list of nets set as ""do not touch"" +return do_not_touch_nets",Get the nets that are set as do not touch and return as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective coupled capacitor adjust orders +net_Cc_adjust_order = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its coupled capacitor adjust order in the dictionary + net_Cc_adjust_order[net.getName()] = net.getCcAdjustOrder() + +# Return the dictionary containing net names and their Cc adjust orders +return net_Cc_adjust_order",Get the coupled capacitor adjust order for the nets of the instance input6 and return the result as a dict with key being net name and value being the coupled capacitor adjust order +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective wire types +net_wire_type = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its wire type in the dictionary + net_wire_type[net.getName()] = net.getWireType() + +# Return the dictionary containing net names and their wire types +return net_wire_type",Get the wire types of the nets connecting to the instance input6 and return the result as a dictionary with key being net name and value being the wire type +"# Get the design block +block = design.getBlock() + +# List to store marked nets +marked_nets = [] + +# List of net names to mark +nets_to_mark = [ + ""resp_msg[4]"", + ""resp_msg[5]"", + ""resp_msg[6]"", + ""resp_msg[7]"", + ""resp_msg[8]"", + ""resp_msg[9]"", + ""resp_rdy"", + ""resp_val"" +] + +# Iterate through each net name +for name in nets_to_mark: + # Find the net object by name + net = block.findNet(name) + + # Set the mark flag of the net to True + net.setMark(True) + + # Append the marked net to the list + marked_nets.append(net) + +# Return the list of marked nets +return marked_nets","Set mark flags to the nets resp_msg[4], resp_msg[5], resp_msg[6], resp_msg[7], resp_msg[8], resp_msg[9], resp_rdy, resp_val and return the list of market nets." +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store selected nets +selected_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is selected + if net.isSelect(): + # Append the net to the list + selected_nets.append(net) + +# Return the list of selected nets +return selected_nets",Get the selected nets +"# Get thedesign block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective total resistances +net_total_resistance = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its total resistance in mil ohms in the dictionary + net_total_resistance[net.getName()] = net.getTotalResistance() + +# Return the dictionary containing net names and their total resistances +return net_total_resistance +","Get the total resistance in mil ohms of the nets connecting to the instance ""input6"" and return the result as a dict using net name as key and resistance as value" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets connected by abutment +abutment_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net have its pins connected by abutment + if net.isConnectedByAbutment(): + # Append the net to the list + abutment_nets.append(net) + +# Return the list of nets connected by abutment +return abutment_nets",Get the nets that have their pins connected by abutment and return as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_699_"" +inst = block.findInst(""_699_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective coupled capacitor match ratio +net_cc_match_ratio = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its coupled capacitor match ratio in the dictionary + net_cc_match_ratio[net.getName()] = net.getCcMatchRatio() + +# Return the dictionary containing net names and their Cc Match ratios +return net_cc_match_ratio +","Get the coupled capacitor match ratio of the nets connecting to the instance ""_699_"" and return as a dict using net name as key and coupled capacitor match ratio as value" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input10"" +inst = block.findInst(""input10"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective node capacitors +net_cap_nodes = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its cap nodes in the dictionary + net_cap_nodes[net.getName()] = net.getCapNodes() + +# Return the dictionary containing net names and their cap nodes +return net_cap_nodes","Get the node capacitor of the RC segment belong to each net connecting to the instance input10, and return the result as a dict with net name being keys and node capacitors as values" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal4"" +layer = tech.findLayer('metal4') +# Return the pitch of the layer +return layer.getPitch()","Get the pitch setting of ""metal 4"" layer" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store extracted nets +extracted_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is extracted + if net.isExtracted(): + # Append the extracted net to the list + extracted_nets.append(net) + +# Return the list of extracted nets +return extracted_nets",Get all extracted nets as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input10"" +inst = block.findInst(""input10"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective routing guides +net_guides = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its routing guides in the dictionary + net_guides[net.getName()] = net.getGuides() + +# Return the dictionary containing net names and their routing guides +return net_guides","Get the routing guides of the nets connecting to the instance ""input10"" as a dictionary, using net name as keys and routing guide as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""FILLER_0_17_13"" +inst = block.findInst(""FILLER_0_17_13"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective tracks +net_tracks = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its tracks in the dictionary + net_tracks[net.getName()] = net.getTracks() + +# Return the dictionary containing net names and their tracks +return net_tracks","Get the tracks of the nets connecting to the instance ""FILLER_0_17_13"", and return it as a dict using net name as keys and tracks as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer29"" +inst = block.findInst(""rebuffer29"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Reverse the coupled capacitor segments of the net + net.reverseCCSegs()",Reverse the coupled capacitor segments of the nets connecting to the instance called rebuffer29 +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer9"" +inst = block.findInst(""rebuffer9"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective driving ITerms +net_driving_iterm = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its driving term id assigned of this net. -1 if not set, 0 if non existent + net_driving_iterm[net.getName()] = net.getDrivingITerm() + +# Return the dictionary containing net names and their driving ITerms +return net_driving_iterm","Get the driving term ids for the nets connecting to the instance rebuffer9, and return the rsult as a dict using net name as keys and driving term ids as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""output52"" +inst = block.findInst(""output52"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Print the net name + print(""Net:"", net.getName()) + + # Print the wire opcodes + net.printWire()",Print the wire opcode information of the the nets connecting to the instance output52 +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_706_"" +inst = block.findInst(""_706_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective Cap node counts +net_cap_node_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its node capacitor count in the dictionary + net_cap_node_count[net.getName()] = net.getCapNodeCount() + +# Return the dictionary containing net names and their Cap node counts +return net_cap_node_count +","Get the node capacitor count of RC segments of the nets connecting to the instance _706_, and return the result as a dictionary with keys being net name, and values being node capacitor count " +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets that are RC graphs +rc_graph_nets = [] + +# Iterate through each net +for net in nets: + # Check if the rc_graph flag set, and the flag is set when Rseg and CapNodes were created + if net.isRCgraph(): + # Append the net to the list + rc_graph_nets.append(net) + +# Return the list of nets that are RC graphs +return rc_graph_nets +","Get all the nets if their rc_graph flag is set, and return the result as a list" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""split30"" +inst = block.findInst(""split30"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective term counts +net_term_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and the amount of pins and ports of this net in the dictionary + net_term_count[net.getName()] = net.getTermCount() + +# Return the dictionary containing net names and their amount of pins and ports +return net_term_count","Get the amount of pins and ports of the nets connecting to the instance ""split30"" and return it as a dictionary with net name being keys" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""clkbuf_0_clknet_2_3__leaf_clk"" +inst = block.findInst(""clkbuf_0_clknet_2_3__leaf_clk"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective x-talk classes +net_X_Talk_class = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its x-talk class in the dictionary + net_X_Talk_class[net.getName()] = net.getXTalkClass() + +# Return the dictionary containing net names and their x-talk classes +return net_X_Talk_class","Get the x-talk-class of the nets connecting to the instance ""clkbuf_0_clknet_2_3__leaf_clk"", as a dictionary with the net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer5"" +inst = block.findInst(""rebuffer5"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective first BTerms +net_first_bterms = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its first BTerm in the dictionary + net_first_bterms[net.getName()] = net.get1stBTerm() + +# Return the dictionary containing net names and their first BTerms +return net_first_bterms","Get the first port of the nets connecting to the instance rebuffer5, as a dictionary with the net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input22"" +inst = block.findInst(""input22"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective R segment counts +net_R_seg_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its R segment count in the dictionary + net_R_seg_count[net.getName()] = net.getRSegCount() + +# Return the dictionary containing net names and their R segment counts +return net_R_seg_count","Get the R segment count of the RC network connected to the nets of the instance input22, return the result as a dictionary with net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_686_"" +inst = block.findInst(""_686_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective nondefault rule applied for wiring +net_non_default_rule = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and the nondefault rule applied to this net for wiring in the dictionary, returns nullptr if there is no nondefault rule. + net_non_default_rule[net.getName()] = net.getNonDefaultRule() + +# Return the dictionary containing net names and their nondefault rule applied to this net for wiring +return net_non_default_rule",Get the nondefault rule applied to the nets connected to the instance _686_ as a dictionary with the net names as key values. +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_706_"" +inst = block.findInst(""_706_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective zeroth R segments +net_zero_R_segment = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its zeroth R segment in the dictionary + net_zero_R_segment[net.getName()] = net.getZeroRSeg() + +# Return the dictionary containing net names and their zeroth R segments +return net_zero_R_segment",Get the zeroth R segment of the nets of the instance _706_ as a dictionary with the net names as key values. +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Dictionary to store layer directions with their names +layer_direction_dict = {} + +# Dictionary to store upper and lower layers of the 'poly' layer +poly_upper_lower_layers = {} + +# Iterate through each layer +for layer in layers: + # Store the direction of the layer with its name in the dictionary + layer_direction_dict[layer.getName()] = layer.getDirection() + + # If the layer name is 'poly', store its upper and lower layers + if layer.getName() == ""poly"": + poly_upper_lower_layers = { + ""upper"": layer.getUpperLayer(), + ""lower"": layer.getLowerLayer() + } + +# Create a result dictionary containing layer directions and 'poly' upper and lower layers +result = { + ""layer_directions"": layer_direction_dict, + ""poly"": poly_upper_lower_layers +} + +# Return the result dictionary +return result","Get the routing directions of the layers with their names as keys and also get the layers above and below the layer with name 'poly'. Finally, return them as dict of dicts" +"# Get the current design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Dictionary to store Capacitance Coupling Match Ratio of each net +net_cc_match_ratio = {} + +# Iterate through each net and store its Capacitance Coupling Match Ratio +for net in nets: + net_cc_match_ratio[net.getName()] = net.getCcMatchRatio() + +# List of net names to set Capacitance Coupling Match Ratio to 1 +nets = [""req_msg[13]"", ""clk""] + +# Iterate through each net name in the list and set its Capacitance Coupling Match Ratio to 1 +for net_name in nets: + net = block.findNet(net_name) + net.setCcMatchRatio(1) + +# Return the dictionary containing Capacitance Coupling Match Ratio of each net +return net_cc_match_ratio +","Calculate the Capacitance Coupling Match Ratio for each net and organize the results into a dictionary. Use the net names as keys and their corresponding Capacitance Coupling Match Ratios as values. Additionally, ensure that the Capacitance Coupling Match Ratios for the nets named ""req_msg[13]"" and ""clk"" are set to 1." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the vias defined in the technology +vias = tech.getVias() + +# Get the Via Count of the technology +via_count = tech.getViaCount() + +# Set the Clearance Measure of the technology to 500 +print(tech.getClearanceMeasure()) + +# Create a dictionary containing vias and the count of vias +result = { + ""vias"": vias, + ""count"": via_count +} + +# Return the result dictionary +return result","Get the vias and via count as a dictionary with ""vias"" and ""count"" as keys, and print the Clearance Measure." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology file +layers = tech.getLayers() + +# Dictionary to store areas of layers with their names +layer_area_dict = {} + +# Iterate through each layer +for layer in layers: + # Store the area of the layer with its name in the dictionary + layer_area_dict[layer.getName()] = layer.getArea() + +# Create a result dictionary containing layer area dictionary and list of layer names +result = { + ""area_dict"": layer_area_dict, + ""layer_names"": list(layer_area_dict.keys()) +} + +# Return the result dictionary +return result","Retrieve the layer names defined in the technology as a list and obtain the corresponding areas of these layers of the technology, associating each area with its respective layer name in a dictionary. Return this result encapsulated in a dictionary with ""area_dict"" representing the areas of the layers and ""layer_names"" representing the list of layer names." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the Via Count of the technology +via_count = tech.getViaCount() + +# Get the Via Generate Rules of the technology +via_rules = tech.getViaGenerateRules() + +# Get the current value of database units per micron and add 500 +db_microns = block.getDbUnitsPerMicron() + 500 + +# Set the new value of database units per micron +tech.setDbUnitsPerMicron(db_microns) + +# Create a dictionary containing via count, via rules, and the updated value of database units per micron +result = { + ""count"": via_count, + ""rules"": via_rules +} + +# Return the result dictionary +return result","Retrieve the via count and via generate rules of the technology. Return the result as a dictionary with ""count"" and ""rules"" as keys for the via count and via generate rules, respectively." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store rotation of the instances whose library cells are of type 'NOR2_X1' +NOR_transform_orient = {} + +# Iterate through each instance +for inst in insts: + # Check if the library cell name is ""NOR2_X1"" + if inst.getMaster().getName() == ""NOR2_X1"": + # Store the rotation of the instance + NOR_transform_orient[inst.getName()] = inst.getTransform().getOrient() + + # Check if the instance name is ""_411_"" or ""input1"" + if inst.getName() == ""_411_"" or inst.getName() == ""input1"": + # Mark the first output net of the instance + inst.getFirstOutput().getNet().setMark(True) + +# Return the dictionary containing orientation of instance +return NOR_transform_orient","Get the rotation of the instances whose library cells are of type 'NOR2_X1' and return as a dict with instance name as keys, and mark the first output nets of the instances '_411_' and 'input1'." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through each instance +for inst in insts: + # Check if the master cell name contains ""NAND2_X1"" + if inst.getMaster().getName() == ""NAND2_X1"": + # Invert the instance + inst.getTransform().invert() + + # Check if the instance name is ""_411_"" or ""input1"" + if inst.getName() == ""_411_"" or inst.getName() == ""input1"": + # Get the transform of the instance + transform = inst.getTransform() + # If the orientation is 'R0', set it to 'MX'; if 'MX', set it to 'R0' + if transform.getOrient() == 'R0': + transform.setOrient('MX') + elif transform.getOrient() == 'MX': + transform.setOrient('R0')",Invert the offset and the rotation of instances whose library cells are 'NAND2_X1' and set the orient of the instance '_411_' to 'R0' if 'MX' or 'MX' if 'R0'. +"# Get the current design block +block = design.getBlock() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Set the orientation of the instance '_411_' to 'MX' +inst.getTransform().setOrient('MX') + +# Get all instances +insts = block.getInsts() + +# Dictionary to store halos of instances +inst_halos = {} + +# Iterate through each instance +for inst in insts: + # Store the halo of the instance in the inst_halos dictionary + inst_halos[inst.getName()] = inst.getHalo() + +# Return the dictionary containing halos of instances +return inst_halos",Set the orientation of the instance '_411_' to 'MX' and retrieve all the halos of instances. Return the result as a dictionary with each instance's name as the key mapped to their halo. +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Initialize lists to store non-core instances and vertical tech layers with capacitance +vertical_layers = [] +non_core_insts = [] + +# Define the direction for the layers +direction = 'VERTICAL' + +# Iterate through each instance +for inst in insts: + # Check if instance is not core instance + if not inst.getMaster().isCore(): + # Add the instance to the list of non-core instances + non_core_insts.append(inst) + +# Iterate through each layer in the technology +for layer in layers: + # Check if the layer direction is VERTICAL + if layer.getDirection() == direction: + # Add the layer and its capacitance to the list of vertical layers + vertical_layers.append((layer, layer.getCapacitance())) + +# Return the list of non-core instances and horizontal layers with their capacitance +return (non_core_insts, horizontal_layers)",Get a list of all the non-core instances and a list of the vertical layers and their capacitance as a list of tuples. +"# Get the current design block +block = design.getBlock() + +# Get all the instances +insts = block.getInsts() + +# Find the instance with the name '_411_' +inst = block.findInst('_411_') + +# Dictionary to store signal types in nets +signal_type_dict = {} + +# Check if instance '411' is type ENDCAP or any of its subtypes +print(""End cap status of cell '_411_':"", inst.isEndCap()) + +# Loop through all instances +for inst in insts: + # Check if any of the user flags are set to true + if inst.getUserFlag1() or inst.getUserFlag2() or inst.getUserFlag3(): + # Set the level of the instance to 1 + inst.setLevel(1) + + # Check if the instance name is 'input1' + if inst.getName() == ""input1"": + # Get the nets connected to 'input1' instance + nets = [pin.getNet() for pin in inst.getITerms()] + + # Iterate through each net + for net in nets: + # Check if the net exists + if net: + # Store the signal type of the net in the dictionary + signal_type_dict[net.getName()] = net.getSigType() + break + +# Return the dictionary containing signal types in nets +return signal_type_dict","Check if the library cell of instance '_411_' is type ENDCAP and get all the instances whose user flags are set and set those instances to level 1, also get the signal types in the nets of instance 'input1'" +"# Set userFlags 1 and 3 true for instance '411' and retrieve the LEQ (Logic Equivalent) information associated with the library cell of instance '411'. + +# Get the dsign block +block = design.getBlock() + +# Find the instance '411' +inst = block.findInst(""_411_"") + +# Set userFlags 1 and 3 true +inst.setUserFlag1() +inst.setUserFlag3() + +# Get the library cell of instance '411' +master = inst.getMaster() + +# Retrieve the LEQ information associated with the library cell +LEQ = master.getLEQ() + +# Return LEQ +return LEQ",Set userFlags 1and 3 true for instance '411' and retrieves the LEQ (Logic Equivalent) information associated with the library cell of instance '411'. +"# Get the location of the instances whose library cell is 'AND2_X1' and get rotation of instance whose library cells are of type 'NAND2_X1'. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store offset of 'AND2_X1' instances and location of 'NAND2_X1' instances +offset_dict_AND = {} +orient_dict_NAND = {} + +# Iterate through instances +for inst in insts: + # Check if the master cell name contains 'AND2_X1' + if inst.getMaster().getName() == ""AND2_X1"": + # Get transform and store offset + transform = inst.getTransform() + offset_dict_AND[inst.getName()] = transform.getOffset() + + # Check if the master cell name contains 'NAND2_X1' + if inst.getMaster().getName() == ""NAND2_X1"": + # Get transform and store location + transform = inst.getTransform() + orient_dict_NAND[inst.getName()] = transform.getOrient() + +# Return dictionaries of offsets and locations +return (offset_dict_AND, orient_dict_NAND)",Get the location of the instances whose library cell is 'AND2_X1' as a dicitonary with instance names as keys and get rotation of instance whose library cells are of type 'NAND2_X1'. +"# Set all the COVER master cells to frozen + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through instances +for inst in insts: + # Get the master of the instance + master = inst.getMaster() + # Check if the master is of type COVER + if master.isCover(): + # Set the COVER master cell to frozen so dbMTerms cannot be added or delete from the master + master.setFrozen()",set all the COVER master cells to frozen +"# Invert transforms of the instances whose master cells are 'NAND2_X1' +# and get the offset of the transform of instance '411' and 'input1'. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store offset of transforms for instances '_411_' and 'input1' +inst_transform_offset = {} + +# Iterate through instances +for inst in insts: + # Check if the master cell name is 'NAND2_X1' + if inst.getMaster().getName() == ""NAND2_X1"": + # Get transform and invert + transform = inst.getTransform() + transform.invert() + + # Check if instance name is '411' or 'input1' + if inst.getName() == '_411_' or inst.getName() == 'input1': + # Get transform and store offset + transform = inst.getTransform() + inst_transform_offset[inst.getName()] = transform.getOffset() + +# Return dictionary containing offsets for instances '411' and 'input1' +return inst_transform_offset","Invert the location and rotation of instances whose library cells are 'NAND2_X1'. Then, retrieve the location of the instances '_411_' and 'input1' and return them as a dictionary with the instance names as keys and their respective location as values." +"# Get All the nets of the instances whose signal type is ""SIGNAL"" and get all the blockages. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# List to store nets with signal type 'SIGNAL' +nets = [] + +# Iterate through instances +for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate through pins + for pin in pins: + # Check if the signal type is 'SIGNAL' + if pin.getSigType() == 'SIGNAL': + # Add the net to the list + nets.append(pin.getNet()) + +# Get all blockages in the block +blockages = block.getBlockages() + +# Return a tuple containing the list of nets and blockages +return (nets, blockages)","Get a list of all the nets of the instances whose signal type is ""SIGNAL"" and get all the blockages. Return the result as a tuple" +"# Get the design block +block =design.getBlock() + +# Reset the tapcell in the design +tapcell = design.getTapcell() +tapcell.reset() + +# Retrieve the coupling capacitance segments +coupling_segments = block.getCCSegs() + +# Return the coupling capacitance segments +return coupling_segments",Reset the tapcell in the design and retrieve the coupling capacitance segments of the design block. +"# Get the list of hierarchical filler cell instances. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# List to store hierarchical instances with filler cells +inst_list = [] + +# Iterate through instances +for inst in insts: + # Check if the instance is hierarchical and its master is a filler cell + if inst.isHierarchical() and inst.getMaster().isFiller(): + inst_list.append(inst) + +# Return hierarchical instances with filler cells +return inst_list",Get the list of hierarchical filler cell instances. +"# Get the resistor segments and get the sites of rows +block = design.getBlock() +resistor_segments = block.getRSegs() + +# Get the sites of rows +rows = block.getRows() +hybrid_rows = {} +for row in rows: + if row.getSite().isHybrid(): + hybrid_rows[row] = row.getSite() + +# Return resistor segments and hybrid rows +return (resistor_segments, hybrid_rows) +","Get the resistor segments and a dictionary of the hybrid sites of the rows, with the row as the key and the site as the value." +"# Get source type of all the instance on level 1 with filler cells and set the placement Status of the instance 'input1' to 'UNPLACED'. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store source types +source_dict = {} + +# Iterate through instances +for inst in insts: + # Check if the instance's master is a filler cell and it is set as level 1 + if inst.getMaster().isFiller() and inst.getLevel() == 1: + # Get and store the source type + source_dict[inst.getName()] = inst.getSourceType() + + # Check if the instance is 'input1' and set its placement status to 'UNPLACED' + if inst.getName() == ""input1"": + inst.setPlacementStatus('UNPLACED') + +# Return source types +return source_dict +","Get source type of all the filler cell instances set as level 1 as a dictionary with inst name as keys. Also, set the placement status flag of the instance 'input1' to 'UNPLACED'." +"# Set the alias of the layers by the naming convention ''LayerXi"" where i is the index of the layer and get the status of USEMINSPACING for pins in LEF. return the results as a dict with each requirement as key names. + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers +layers = tech.getLayers() + +# Initialize a dictionary to store the Alias of each layer +layer_alias = {} + +# Iterate through all layers +for layer in layers: + # Construct the Alias using the layer index + alias = ""LayerX"" + str(layer.getNumber()) + + # Set the Alias of the layer + layer.setAlias(alias) + + # Store the Alias of the layer in the dictionary + layer_alias[layer.getName()] = alias + +# Get the status of USEMINSPACING for pins in LEF +min_spacing_pin = tech.getUseMinSpacingPin() + +# Return the dictionary containing the updated Alias of layers +return { + ""Alias"": layer_alias, + ""min_spacing_pin"": min_spacing_pin +}","Set the alias of the layers by the naming convention ''LayerXi"" where i is the index of the layer and get the status of USEMINSPACING for pins in LEF. return the results as a dict with each requirement as key names." +"# Get the current block of the design +block = design.getBlock() + +# Find the instances '_411_' and 'input1' +inst1 = block.findInst('_411_') +inst2 = block.findInst('input1') + +# Get the library cells of the instances +master1 = inst1.getMaster() +master2 = inst2.getMaster() + +# Get the MTerms of the library cell of the instance '_411_' +mterms1 = master1.getMTerms() + +# Get the MTerms of the library cell of the instance 'input1' +mterms2 = master2.getMTerms() + +# List to store input MTerms of the instance 'input1' +input_mterms = [] + +# Iterate through each MTerm of the instance 'input1' +for mterm in mterms2: + # Check if the IoType is 'INPUT' + if mterm.getIoType() == 'INPUT': + # Append the MTerm to the list of input MTerms + input_mterms.append(mterm) + +# Return a tuple containing MTerms of the library cell of instance '_411_' and input MTerms of instance '_411_' +return (mterms1, input_mterms)",Get the MTerms of the library cell of the instance '_411_' and get the list of mterms of the instance 'input1' whose IoType is 'INPUT'. Return the results as a tuple +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the LEF version of the technology +lef_version = tech.getLefVersion() + +# get clearance measure of the technology +clearance_measure = tech.getClearanceMeasure() + +# Set Db units per micron to 1500 for the chip +tech.setDbUnitsPerMicron(1500) + +# Return the clearance measure and the LEF version of the technology +return (clearance_measure, lef_version)",Get the clearance measure and set the Db units per micron to 1500 to the chip and get Lef version. return the result as a tuple. +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Find the layer 'metal5' in the technology +layer = tech.findLayer('metal5') + +# Get the upper and lower layers of the layer 'metal5' +upper_lower_layer = { + ""upper"": layer.getUpperLayer(), + ""lower"": layer.getLowerLayer() +} + +# Get the top layer of the IO Placer object of the design +iop = design.getIOPlacer() +iop_top_layer = iop.getTopLayer() + +# Return a tuple containing the upper and lower layer of 'metal5' and the top layer used for the IO pin placer +return (upper_lower_layer, iop_top_layer)","Retrieve the upper and lower layers of the 'metal5' layer and encapsulate them in a dictionary with ""upper"" and ""lower"" as keys. Additionally, retrieve the setting of the top layer used for the IO pin placer. Return the results as a tuple." +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Initialize a list to store output pins without nets +output_pin_wout_net = [] +# Iterate over instances +for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate over pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets == None: + # Append the pin to the list + output_pin_wout_net.append(pin) +# Check if there are no output pins without nets +if len(output_pin_wout_net) == 0: + return True +else: + return False ",Check if all the output pins of all instances have a valid net connection +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Initialize a list to store input pins without nets +input_pin_wout_net = [] +# Iterate over instances +for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate over pins + for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets == None: + # Append the pin to the list + input_pin_wout_net.append(pin) +# Check if there are no input pins without nets +if len(input_pin_wout_net) == 0: + return True +else: + return False",Check if all the input pins of all instances have a valid net connection +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_split30_"" +inst = block.findInst(""_split30_"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","Set the instance ""_split30_"" as don't touch type" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_split30_"" +inst = block.findInst(""_split30_"") +# Set the instance as don't touch type +inst.setDoNotTouch(False)","Reset the instance ""_split30_"" as don't touch type" +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store pin names +pin_name_list = [] +# Loop through all instances +for inst in insts: + # Get the pins of this instance + inst_ITerms = inst.getITerms() + # Loop through all pins + for ITerm in inst_ITerms: + # Append pin names to the list + pin_name_list.append(design.getITermName(ITerm)) +return pin_name_list",Get the name of every pin +"# Get the placement status of all instances + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store unplaced instances +unplaced_instances = [] + +# Iterate through all instances +for inst in insts: + # Print the instance name and its placement status + print(inst.getName(), inst.getPlacementStatus()) + # Check if the instance is not placed + if not inst.isPlaced(): + # If the instance is not placed, add it to the list of unplaced instances + unplaced_instances.append(inst) + +# Return the list of unplaced instances +return unplaced_instances +",get the all the unplaced instance as a list +"# Get the design block +block = ord.get_db_block() +# Get instances from +insts = block.getInsts() +# Initialize a dictionary to store instances with MUX2_X2 master +mux_ins_dict = {} + +# Iterate over instances +for inst in insts: + # Get the master of the instance + mast = inst.getMaster() + # Check if the master is MUX2_X2 + if 'MUX2_X2' == mast.getName(): + # Check if instance name is already in the dictionary + if inst.getName() not in mux_ins_dict: + mux_ins_dict[inst.getName()] = [mast.getName()] + else: + mux_ins_dict[inst.getName()].append(mast.getName()) + +# Return the dictionary +return mux_ins_dict","Return a dictionary with the keys being the names of all MUX2_X2 cells, and the values being the name of the library cell" +"# Get the nets of all input pins + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store nets of input pins +input_net_list = [] + +# Iterate through all instances +for inst in insts: + # Get all input pins (ITerms) of the instance + pins = inst.getITerms() + # Iterate through all input pins + for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal(): + # If it's an input signal, add its net to the list + input_net_list.append(pin.getNet()) + +# Return the list of nets of input pins +return input_net_list",Get the nets of all input pins +"# Get the nets of all output pins + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store nets of output pins +output_net_list = [] + +# Iterate through all instances +for inst in insts: + # Get all input pins (ITerms) of the instance + pins = inst.getITerms() + # Iterate through all input pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # If it's an output signal, add its net to the list + output_net_list.append(pin.getNet()) + +# Return the list of nets of output pins +return output_net_list",get the nets of all output pins +"# Get each net's fanout count, in the form of a dictionary, with net name as key and number of fanout as value +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a dictionary to store fanout information +fanout_dict = {} + +# Iterate through all instances +for inst in insts: + # Get all pins (ITerms) of the instance + pins = inst.getITerms() + # Iterate through all pins + for pin in pins: + # Get the net associated with the pin + net = pin.getNet() + # Get the name of the net + name = net.getName() if net else None + # Check if the pin is an input signal + if pin.isInputSignal(): + # If it's an input signal, increment the fanout count for the net + if name in fanout_dict: + fanout_dict[name] += 1 + else: + fanout_dict[name] = 1 + else: + # If it's not an input signal, initialize the fanout count for the net to 0 + if name not in fanout_dict: + fanout_dict[name] = 0 + +# Return the fanout dictionary +return fanout_dict","Get each net's fanout count, in the form of a dictionary, with net name as key and number of fanout as value" +"# Get all the instances on level 0 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Level to filter instances +level = 0 + +# Initialize a list to store instances on the specified level +insts_on_level = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance's level matches the specified level + if inst.getLevel() == level: + # If it's on the specified level, add it to the list + insts_on_level.append(inst) + +# Return the list of instances on the specified level +return insts_on_level",Get all the instances on level 0 +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst('input20') +# Set the orientation of the instance as ""R0"" +inst.setOrient('R0')",Set the orientation of an instance 'input20' as 'R0' +"# Get the output pins of the instance 'output53' + +# Get the design block +block = design.getBlock() + +# Get all instances +inst = block.findInst('output53') + +# Initialize a variable to store the output pin +output_pins = [] + +# Get all input pins (ITerms) of the instance +pins = inst.getITerms() + +# Iterate through all input pins +for pin in pins: + # Check if the pin is an output signal + if pin and pin.isOutputSignal() : + # If it's an output signal, store it as the output pin + output_pins.append(pin) + +# Return the output pin of the specified instance +return output_pins",get the output pins of the instance 'output53' +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store instances with pins set as clocked +clock_insts = [] + +# Iterate through all instances +for inst in insts: + + pins = inst.getITerms() + for pin in pins: + if pin.isClocked(): + clock_insts.append(inst) + +# Return the list of instances with pins set as clocked +return clock_insts",get the instances that have pins set as clocked +"# Get all the pins whose 'IO type' is 'INPUT'. + +# Get the design block +block = design.getBlock() + +# Get all pins (ITerms) +pins = block.getITerms() + +# Initialize a list to store input pins +input_pins = [] + +# Iterate through all pins +for pin in pins: + # Check if the pin's IO type is INPUT + if pin.getIoType() == 'INPUT': + # If it's an input pin, add it to the list + input_pins.append(pin) + +# Return the list of input pins +return input_pins",Get all the pins whose 'IO type' is 'INPUT'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the DB units per micron +return block.getDbUnitsPerMicron()",Convert 1 micron to units used in this technology in OpenROAD +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the DB units per micron +return block.getDbUnitsPerMicron()",Convert 1 micrometer to units used in this technology in OpenROAD +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst(""input1"") +# Check if the user-defined flag 1 of the instance is set true +if inst.getUserFlag1()==True: + # Clear the user flag 1 of the instance + inst.clearUserFlag1()","Clear the user-defined flag 1 on the instance with name ""input1"" if the flag is set" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name 'poly' +layer = tech.findLayer('poly') +# Return the layer above the layer +return layer.getUpperLayer()",Get the layer above the layer with name 'poly' +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Initialize a list to store output pins without nets +output_pin_wout_net = [] +# Iterate over instances +for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate over pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets == None: + # Append the pin to the list + output_pin_wout_net.append(pin) +# Check if there are no output pins without nets +if len(output_pin_wout_net) == 0: + return True +else: + return False ",Check if all the output pins of all instances have a valid net connection +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Initialize a list to store input pins without nets +input_pin_wout_net = [] +# Iterate over instances +for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate over pins + for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets == None: + # Append the pin to the list + input_pin_wout_net.append(pin) +# Check if there are no input pins without nets +if len(input_pin_wout_net) == 0: + return True +else: + return False",Check if all the input pins of all instances have a valid net connection +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Define the fanout threshold +gt_fanout = 6 +# Initialize a list to store nets with fanout greater than the threshold +net_fanout = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) > gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) +# Return the list of nets with fanout greater than the threshold +return net_fanout",Give me a list of nets with a fanout greater than 6 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Define the fanout threshold +gt_fanout = 6 +# Initialize a list to store nets with fanout greater than the threshold +net_fanout = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) < gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) +# Return the list of nets with fanout greater than the threshold +return net_fanout",Give me a list of nets with a fanout less than 6 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Define the fanout threshold +gt_fanout = 5 +# Initialize a list to store nets with fanout greater than the threshold +net_fanout = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) > gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) +# Return the list of nets with fanout greater than the threshold +return net_fanout",Give me a list of nets with a fanout greater than 5 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Define the fanout threshold +gt_fanout = 5 +# Initialize a list to store nets with fanout greater than the threshold +net_fanout = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) < gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) +# Return the list of nets with fanout greater than the threshold +return net_fanout",Give me a list of nets with a fanout less than 5 +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the def units to 1500 as mentioned in the prompt +block.setDefUnits(1500)",Set the def units to 1500 +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 5 ns as mentioned in the prompt + if pin_rise_arr >= 5e-9: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 5 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 132 ps as mentioned in the prompt + if pin_rise_arr >= 1.32e-10: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 132 ps and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 132 picosecond as mentioned in the prompt + if pin_rise_arr >= 1.32e-10: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 132 picosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 5 nanosecond as mentioned in the prompt + if pin_rise_arr >= 5e-9: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 5 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 18 nanosecond as mentioned in the prompt + if pin_rise_arr >= 1.8e-8: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 18 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 18 ns as mentioned in the prompt + if pin_rise_arr >= 1.8e-8: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 18 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 142 ns as mentioned in the prompt + if pin_rise_arr >= 1.42e-7: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 142 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 142 nanosecond as mentioned in the prompt + if pin_rise_arr >= 1.42e-7: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 142 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 321 ns as mentioned in the prompt + if pin_rise_arr >= 3.21e-7: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 321 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 321 nanosecond as mentioned in the prompt + if pin_rise_arr >= 3.21e-7: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 321 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 28 ns as mentioned in the prompt + if pin_rise_arr >= 2.8e-8: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 28 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than or equal 28 nanosecond as mentioned in the prompt + if pin_rise_arr >= 2.8e-8: + output.append(pin) +return output",Get all the pins which has a pin rising arrival time greater than or equal to 28 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rise arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rise arrival time is greater than or equal 6 nanoseconds as mentioned in the prompt + if pin_rise_arr >= 0.000000006: + output.append(pin) +return output",Get all the pins which has a pin rise arrival time greater than or equal to 6 nanoseconds in the block and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rise arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rise arrival time is less than or equal 0.4 second as mentioned in the prompt + if pin_rise_arr <= 0.4: + # Append the pin to the output + output.append(pin) +return output",Get all the pins which has a pin rise arrival time less than or equal to 0.4 seconds in the block and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the fall arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the fall arrival time is less than or equal to 0.1 seconds as mentioned in the prompt + if pin_fall_arr <= 0.1: + # Append the pin to the output + output.append(pin) +return output",Get all the pins which has a pin fall arrival time less than or equal to 0.1 second in the block and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 5 ns as mentioned in the prompt + if pin_rise_arr >= 5e-9: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 5 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 132 ps as mentioned in the prompt + if pin_rise_arr >= 1.32e-10: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 132 ps and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 132 picosecond + if pin_rise_arr >= 1.32e-10: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 132 picosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 5 nanosecond as mentioned in the prompt + if pin_rise_arr >= 5e-9: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 5 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 18 nanosecond as mentioned in the prompt + if pin_rise_arr >= 1.8e-8: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 18 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 18 ns as mentioned in the prompt + if pin_rise_arr >= 1.8e-8: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 18 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 142 ns as mentioned in the prompt + if pin_rise_arr >= 1.42e-7: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 142 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 142 nanosecond as mentioned in the prompt + if pin_rise_arr >= 1.42e-7: + output.append(pin) +return output",Get all the pins which has a pin falling arrival time greater than or equal to 142 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is less than or equal to 0.1 seconds as mentioned in the prompt + if pin_fall_arr <= 0.1: + # Append the pin to the output + output.append(pin) +return output",Get all the pins which has a falling arrival time less than or equal to 0.1 second in the block and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 8 ns as mentioned in the prompt + if pin_rise_arr >= 8e-9: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 8 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 118 ps as mentioned in the prompt + if pin_rise_arr >= 1.18e-10: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 118 ps and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 118 picosecond + if pin_rise_arr >= 1.18e-10: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 118 picosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 9 nanosecond as mentioned in the prompt + if pin_rise_arr >= 9e-9: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 9 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 18 nanosecond as mentioned in the prompt + if pin_rise_arr >= 0.000000018: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 18 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 18 ns as mentioned in the prompt + if pin_rise_arr >= 0.000000018: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 18 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 142 ns as mentioned in the prompt + if pin_rise_arr >= 0.000000142: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 142 ns and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins belong to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the falling arrival time is greater than or equal 142 nanosecond as mentioned in the prompt + if pin_rise_arr >= 0.000000142: + output.append(pin) +return output",Get all the pins which has a falling arrival time greater than or equal to 142 nanosecond and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input2"" as mentioned in the prompt +inst = block.findInst(""input2"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the X Minimum of the bounding box of the instance +xmin = BBox.xMin() +# Get the Y Minimum of the bounding box of the instance +ymin = BBox.yMin() +# Get the X Maximum of the bounding box of the instance +xmax = BBox.xMax() +# Get the Y Maximum of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Give me the bounding box of the instance ""input2"", and provide a list of coordinates, with (Xmin, Ymin) in one list, and (Xmax, Ymax) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""input2"" as mentioned in the prompt +inst = block.findInst(""input2"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the x_min of the bounding box of the instance +xmin = BBox.xMin() +# Get the y_min of the bounding box of the instance +ymin = BBox.yMin() +# Get the x_max of the bounding box of the instance +xmax = BBox.xMax() +# Get the y_max of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""input2"", and provide a list of coordinates, with (x_min, y_min) in one list, and (x_max, y_max) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the X Minimum of the bounding box of the instance +xmin = BBox.xMin() +# Get the Y Minimum of the bounding box of the instance +ymin = BBox.yMin() +# Get the X Maximum of the bounding box of the instance +xmax = BBox.xMax() +# Get the Y Maximum of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""_cell1\_124_"", and provide a list of coordinates, with (Xmin, Ymin) in one list, and (Xmax, Ymax) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the x_min of the bounding box of the instance +xmin = BBox.xMin() +# Get the y_min of the bounding box of the instance +ymin = BBox.yMin() +# Get the x_max of the bounding box of the instance +xmax = BBox.xMax() +# Get the y_max of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""_cell1\_124_"", and provide a list of coordinates, with (x_min, y_min) in one list, and (x_max, y_max) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_buff132_"" +inst = block.findInst(""_buff132_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the X Minimum of the bounding box of the instance +xmin = BBox.xMin() +# Get the Y Minimum of the bounding box of the instance +ymin = BBox.yMin() +# Get the X Maximum of the bounding box of the instance +xmax = BBox.xMax() +# Get the Y Maximum of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Give me the bounding box of the instance ""_buff132_"", and provide a list of coordinates, with (Xmin, Ymin) in one list, and (Xmax, Ymax) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_buff132_"" +inst = block.findInst(""_buff132_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the x_min of the bounding box of the instance +xmin = BBox.xMin() +# Get the y_min of the bounding box of the instance +ymin = BBox.yMin() +# Get the x_max of the bounding box of the instance +xmax = BBox.xMax() +# Get the y_max of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""_buff132_"", and provide a list of coordinates, with (x_min, y_min) in one list, and (x_max, y_max) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_buff132_"" +inst = block.findInst(""_buff132_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the Min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the Min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the Max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the Max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""_buff132_"", and provide a list of coordinates, with (Min_x, Min_y) in one list, and (Max_x, Max_y) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_buff132_"" +inst = block.findInst(""_buff132_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""_buff132_"", and provide a list of coordinates, with (min_x, min_y) in one list, and (max_x, max_y) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""temp_inst"" +inst = block.findInst(""temp_inst"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the Min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the Min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the Max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the Max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Retrieve the bounding box of the instance ""temp_inst"", and provide a list of coordinates, with (Min_x, Min_y) in one list, and (Max_x, Max_y) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""temp_inst"" +inst = block.findInst(""temp_inst"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","Give me the bounding box of the instance ""temp_inst"", and provide a list of coordinates, with (min_x, min_y) in one list, and (max_x, max_y) in the next list" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""inst01"" +inst = block.findInst(""inst01"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the Min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the Min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the Max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the Max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","How can I get the bounding box of the instance ""inst01"", and provide a list of coordinates, with (Min_x, Min_y) in one list, and (Max_x, Max_y) in the next list?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""temp_inst"" +inst = block.findInst(""temp_inst"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the min_x of the bounding box of the instance +xmin = BBox.xMin() +# Get the min_y of the bounding box of the instance +ymin = BBox.yMin() +# Get the max_x of the bounding box of the instance +xmax = BBox.xMax() +# Get the max_y of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","How can I get the bounding box of the instance ""temp_inst"", and provide a list of coordinates, with (min_x, min_y) in one list, and (max_x, max_y) in the next list?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the X Minimum of the bounding box of the instance +xmin = BBox.xMin() +# Get the Y Minimum of the bounding box of the instance +ymin = BBox.yMin() +# Get the X Maximum of the bounding box of the instance +xmax = BBox.xMax() +# Get the Y Maximum of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","How can I get the bounding box of the instance ""_cell1\_124_"", and provide a list of coordinates, with (Xmin, Ymin) in one list, and (Xmax, Ymax) in the next list?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Get the Bounding box of the instance +BBox = inst.getBBox() +# Get the x minimum of the bounding box of the instance +xmin = BBox.xMin() +# Get the y minimum of the bounding box of the instance +ymin = BBox.yMin() +# Get the x maximum of the bounding box of the instance +xmax = BBox.xMax() +# Get the y maximum of the bounding box of the instance +ymax = BBox.yMax() +return [[xmin,ymin],[xmax,ymax]]","How can I get the bounding box of the instance ""_cell1\_124_"", and provide a list of coordinates, with (xmin, ymin) in one list, and (xmax, ymax) in the next list?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1200 as mentioned in the prompt +block.setDefUnits(1200)",Establish the units per micron as 1200. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1200 as mentioned in the prompt +block.setDefUnits(1200)",Set the units per micron to 1200. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1200 as mentioned in the prompt +block.setDefUnits(1200)",Set the DEF units of this technology to 1200. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1200 as mentioned in the prompt +block.setDefUnits(1200)",How can I set the DEF units of this technology to 1200? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1600 as mentioned in the prompt +block.setDefUnits(1600)",Establish the units per micron as 1600. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1600 as mentioned in the prompt +block.setDefUnits(1600)",Set the units per micron to 1600. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1600 as mentioned in the prompt +block.setDefUnits(1600)",Set the DEF units of this technology to 1600. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1600 as mentioned in the prompt +block.setDefUnits(1600)",How can I set the DEF units of this technology to 1600? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1500 as mentioned in the prompt +block.setDefUnits(1500)",Establish the units per micron as 1500. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1500 as mentioned in the prompt +block.setDefUnits(1500)",Set the units per micron to 1500. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1500 as mentioned in the prompt +block.setDefUnits(1500)",Set the DEF units of this technology to 1500. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the DEF units of this technology to 1500 as mentioned in the prompt +block.setDefUnits(1500)",How can I set the DEF units of this technology to 1500? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input2' as mentioned in the prompt +inst = block.findInst(""input2"") +inst.setUserFlag1()","Assign the value of true for user-defined flag 1 for the instance named ""input2""." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name 'input3' as mentioned in the prompt +inst = block.findInst('input3') +# Get all the pins connected to an instance +pins = inst.getITerms() +# Initialize a nets array +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Initialize the count with 0 +count = 0 +# Iterate through all the nets +for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + # Increase the count + count+=1 +return count",Provide the count of modified nets connected to the instance 'input3'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_cell1\_124_' as mentioned in the prompt +inst = block.findInst('_cell1\_124_') +# Get all the pins connected to an instance +pins = inst.getITerms() +# Initialize a nets array +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Initialize the count with 0 +count = 0 +# Iterate through all the nets +for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + # Increase the count + count+=1 +return count",Provide the count of modified nets connected to the instance '_cell1\_124_'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_buff132_' +inst = block.findInst('_buff132_') +# Get all the pins connected to an instance +pins = inst.getITerms() +# Initialize a nets array +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Initialize the count with 0 +count = 0 +# Iterate through all the nets +for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + # Increase the count + count+=1 +return count",Provide the count of modified nets connected to the instance '_buff132_'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name 'input2' +inst = block.findInst('input2') +# Get all the pins connected to an instance +pins = inst.getITerms() +# Initialize a nets array +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Initialize the count with 0 +count = 0 +# Iterate through all the nets +for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + # Increase the count + count+=1 +return count",Provide the count of modified nets connected to the instance 'input2'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name 'input4' as mentioned in the prompt +inst = block.findInst('input4') +# Get all the pins connected to an instance +pins = inst.getITerms() +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Iterate through all the nets +for net in nets: + # Check if the wire is altered + if net.isWireAltered(): + return True +return False","Examine all nets connected to the instance 'input4' to see if any have been modified. Return True if modified, and False otherwise." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_buff132_' as mentioned in the prompt +inst = block.findInst('_buff132_') +# Get all the pins connected to an instance +pins = inst.getITerms() +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Iterate through all the nets +for net in nets: + # Check if the wire is altered + if net.isWireAltered(): + return True +return False","Examine all nets connected to the instance '_buff132_' to see if any have been modified. Return True if modified, and False otherwise." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_buff132_' +inst = block.findInst('_buff132_') +# Get all the pins connected to an instance +pins = inst.getITerms() +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Iterate through all the nets +for net in nets: + # Check if the wire is altered + if net.isWireAltered(): + return True +return False","Help me write a piece of code that examine all nets connected to the instance '_buff132_' to see if any have been modified. Return True if modified, and False otherwise." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_cell1\_124_' +inst = block.findInst('_cell1\_124_') +# Get all the pins connected to an instance +pins = inst.getITerms() +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Iterate through all the nets +for net in nets: + # Check if the wire is altered + if net.isWireAltered(): + return True +return False","Examine all nets connected to the instance '_cell1\_124_' to see if any have been modified. Return True if modified, and False otherwise." +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find an instance with name '_cell1\_124_' as mentioned in the prompt +inst = block.findInst('_cell1\_124_') +# Get all the pins connected to an instance +pins = inst.getITerms() +nets = [] +# Iterate through all the pins +for pin in pins: + # Get the net the pin + nets.append(pin.getNet()) +# Iterate through all the nets +for net in nets: + # Check if the wire is altered + if net.isWireAltered(): + return True +return False","Help me write a piece of code that examine all nets connected to the instance '_cell1\_124_' to see if any have been modified. Return True if modified, and False otherwise." +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","Set the instance ""input03"" as don't touch type" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","How can I set the instance ""input03"" as don't touch?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","Set the instance ""_cell1\_124_"" as don't touch type" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","How can I set the instance ""_cell1\_124_"" as don't touch?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","Reset the instance ""input03""'s don't touch flag" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","How can I reset the instance ""input03""'s don't touch flag?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","Reset the instance ""_cell1\_124_""'s don't touch flag" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","How can I reset the instance ""_cell1\_124_""'s don't touch flag?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","Reset the instance ""input03""'s don't touch setting" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","How can I reset the instance ""input03""'s don't touch setting?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","Reset the instance ""_cell1\_124_""'s don't touch setting" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_cell1\_124_"" +inst = block.findInst(""_cell1\_124_"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","How can I reset the instance ""_cell1\_124_""'s don't touch setting?" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","Reset the don't touch setting of instance ""input03""" +"# Get the design block +block = ord.get_db_block() +# Find the instance ""input03"" +inst = block.findInst(""input03"") +# Reset the instance's don't touch flag +inst.setDoNotTouch(False)","How can I reset the don't touch setting of instance ""input03""?" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the number of layers in this technology. +return tech.getLayerCount()",Retrieve the count of layers in this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the number of layers in this technology. +return tech.getLayerCount()",How can I get the count of layers in this technology? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the number of layers in this technology. +return tech.getLayerCount()",Write a piece of code help me get the amount of layers in this technology +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the count of types of vias supported by this technology. +return tech.getViaCount()",Retrieve the count of types of vias supported by this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the count of types of vias supported by this technology. +return tech.getViaCount()",How can I get the count of types of vias supported by this technology? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Return the count of types of vias supported by this technology. +return tech.getViaCount()",Write a piece of code to get the count of types of vias supported by this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'metal1' layer +layer = tech.findLayer('metal1') +# Return the layer above the layer +return layer.getUpperLayer()",Retrieve the layer above the layer named 'metal1'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'M3' layer +layer = tech.findLayer('M3') +# Return the layer above the layer +return layer.getUpperLayer()",Give me the technology layer above the layer named 'M3'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'metal1' layer +layer = tech.findLayer('metal1') +# Return the layer above the layer +return layer.getUpperLayer()",Help me get the layer above the layer named 'metal1'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'metal2' layer +layer = tech.findLayer('metal2') +# Return the layer above the layer +return layer.getUpperLayer()",How can I get the layer above the layer named 'metal2'? +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'Via3' layer +layer = tech.findLayer('Via3') +# Return the layer above the layer +return layer.getUpperLayer()",Give me the technology layer above the layer named 'Via3'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'via3' layer +layer = tech.findLayer('via3') +# Return the layer above the layer +return layer.getUpperLayer()",Give me the technology layer above the layer named 'via3'. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology info +tech = block.getTech() +# Find the 'M4' layer +layer = tech.findLayer('M4') +# Return the layer above the layer +return layer.getUpperLayer()",Help me get the layer above the layer named 'M4'. +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check the placement status +inst_name = 'FILLER_0_3_49' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",Verify if the instance 'FILLER_0_3_49' is placed or not +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check the placement status +inst_name = 'input3' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",Verify if the instance 'input3' is placed or not +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check the placement status +inst_name = 'input3' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",How can I know if the instance 'input3' is placed or not? +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check the placement status +inst_name = 'input3' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",Help me write a piece of script to know if the instance 'input3' is placed or not +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Name of the instance to check the placement status +inst_name = 'cell_12\132' + +# Iterate through all instances +for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Return the placement status of the instance + return inst.isPlaced()",Help me write a piece of script to know if the instance 'cell_12\132' is placed or not +"# Get the design block +block = design.getBlock() + +# Find the instance with name 'PHY_21' +inst = block.findInst('PHY_21') + +# Get the MTerms +mterms = inst.getMaster().getMTerms() + +# Return the MTerms +return mterms +"," +# Retrieve the MTerms of the master cell of the instance 'PHY_21'" +"# Get the design block +block = design.getBlock() + +# Retrieve all instances +insts = block.getInsts() + +# Initialize an empty list to store instances with INV_X1 cell +inst_list = [] + +# Iterate over each instance in the design +for inst in insts: + # Get the master of the current instance + master = inst.getMaster() + # Check if the master's name matches ""INV_X1"" + if master.getName() == ""INV_X1"": + # Append the current instance to the list + inst_list.append(inst) + +# Return the list of instances with INV_X1 cell +return inst_list",get the instances with INV_X1 cell +"# Get length and width of the bounding box of the instance '_590_' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_590_') + +# Get the length and width of the bounding box of the instance +length = inst.getBBox().getLength() +width = inst.getBBox().getWidth() + +# Return the length and width +return (length, width)",Help me get the length and width of the bounding box of the instance '_590_' +"# Get length and width of the bounding box of the instance '_590_' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_590_') + +# Get the length and width of the bounding box of the instance +length = inst.getBBox().getLength() +width = inst.getBBox().getWidth() + +# Return the length and width +return (length, width)",How can I get the length and width of the bounding box of the instance '_590_'? +"# Get length and width of the bounding box of the instance 'input118' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input118') + +# Get the length and width of the bounding box of the instance +length = inst.getBBox().getLength() +width = inst.getBBox().getWidth() + +# Return the length and width +return (length, width)",Help me get the length and width of the bounding box of the instance 'input118' +"# Get length and width of the bounding box of the instance 'input118' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('input118') + +# Get the length and width of the bounding box of the instance +length = inst.getBBox().getLength() +width = inst.getBBox().getWidth() + +# Return the length and width +return (length, width)",How can I get the length and width of the bounding box of the instance 'input118'? +"# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store offset of 'MUX2_X1' +offset_dict = {} + +# Iterate through instances +for inst in insts: + # Check if the master cell name contains 'MUX2_X1' + if inst.getMaster().getName() == ""MUX2_X1"": + # Get the offset + transform = inst.getTransform() + offset_dict[inst.getName()] = transform.getOffset() + +# Return dictionary +return offset_dict",get the offset of the instances whose library cell is 'MUX2_X1' +"# Get the IoType of the MTerms of the instance '_575_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_575_' +inst = block.findInst('_575_') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",get the IoType of the mterms of the instance '_575_' +"# Get the IoType of the MTerms of the instance 'split22' + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'split22' +inst = block.findInst('split22') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",get the IoType of the mterms of the instance 'split22' +"# Get the IoType of the MTerms of the instance 'split22' + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'split22' +inst = block.findInst('split22') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",How can I get the IoType of the mterms of the instance 'split22'? +"# Check if the instance '_373_' has any pin set as clocked + +# Get the design block +block = design.getBlock() + +# Find the instance '_373_' +inst = block.findInst('_373_') + +# Get all pins of the instance +pins = inst.getITerms() + +# List to store pins are set as clocked +clocked_ports = [] + +# Check if any pin is set as clocked +for pin in pins: + if pin.isClocked(): + clocked_ports.append(pin) + +# Return clocked ports +return clocked_ports",Check if the instance '_373_' has any pin set as clocked +"# Check if the instance '_373_' has any pin set as clocked + +# Get the design block +block = design.getBlock() + +# Find the instance '_373_' +inst = block.findInst('_373_') + +# Get all pins of the instance +pins = inst.getITerms() + +# List to store pins are set as clocked +clocked_ports = [] + +# Check if any pin is set as clocked +for pin in pins: + if pin.isClocked(): + clocked_ports.append(pin) + +# Return clocked ports +return clocked_ports",How can I know if the instance '_373_' has any pin set as clocked? +"# Check if the instance 'input112' has any pin set as clocked + +# Get the design block +block = design.getBlock() + +# Find the instance 'input112' +inst = block.findInst('input112') + +# Get all pins of the instance +pins = inst.getITerms() + +# List to store pins are set as clocked +clocked_ports = [] + +# Check if any pin is set as clocked +for pin in pins: + if pin.isClocked(): + clocked_ports.append(pin) + +# Return clocked ports +return clocked_ports",How can I know if the instance 'input112' has any pin set as clocked? +"# Get the design block +block = ord.get_db_block() +# Initialize a list to store clock nets +clock_nets = [] +# Get all nets +nets = block.getNets() +# Iterate over nets +for net in nets: + # Check if the net is a CLOCK net + if net.getSigType() == 'CLOCK': + # Check if the net is a CLOCK net + clock_nets.append(net) +# Check if CLOCK nets exist +if len(clock_nets) > 0: + return True +else: + return False",How can I know if the design has any clock nets? +"# Get the design block +block = ord.get_db_block() +# Initialize a list to store clock nets +clock_nets = [] +# Get all nets +nets = block.getNets() +# Iterate over nets +for net in nets: + # Check if the net is a CLOCK net + if net.getSigType() == 'CLOCK': + # Check if the net is a CLOCK net + clock_nets.append(net) +# Check if CLOCK nets exist +if len(clock_nets) > 0: + return True +else: + return False",Writre a piece of code to see if the design has any clock nets +"# Get the design block +block = ord.get_db_block() +# Initialize a list to store clock nets +clock_nets = [] +# Get all nets +nets = block.getNets() +# Iterate over nets +for net in nets: + # Check if the net is a CLOCK net + if net.getSigType() == 'CLOCK': + # Check if the net is a CLOCK net + clock_nets.append(net) +# Check if CLOCK nets exist +if len(clock_nets) > 0: + return True +else: + return False",Give me the code to see if the design has any clock nets using OpenROAD Python API +"# Get the IoType of the MTerms of the instance 'split22' + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'split22' +inst = block.findInst('split22') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",get the IoType of the mterms of the instance 'split22' using OpenROAD Python API +"# Get the IoType of the MTerms of the instance 'split22' + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'split22' +inst = block.findInst('split22') + +# Get the MTerms of the master cell +mterms = inst.getMaster().getMTerms() + +# Initialize a dictionary to store IoTypes +iotype_dict = {} + +# Iterate through all MTerms +for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + +# Return the dictionary containing IoTypes +return iotype_dict",How can I get the IoType of the mterms of the instance 'split22' using OpenROAD Python API? +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store pin names +pin_name_list = [] +# Loop through all instances +for inst in insts: + # Get the pins of this instance + inst_ITerms = inst.getITerms() + # Loop through all pins + for ITerm in inst_ITerms: + # Append pin names to the list + pin_name_list.append(design.getITermName(ITerm)) +return pin_name_list",How can I put the name of every pin into a list? +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store pin names +pin_name_list = [] +# Loop through all instances +for inst in insts: + # Get the pins of this instance + inst_ITerms = inst.getITerms() + # Loop through all pins + for ITerm in inst_ITerms: + # Append pin names to the list + pin_name_list.append(design.getITermName(ITerm)) +return pin_name_list",Show me how to put every pin's name into a list +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store the name of the instance and its bottom-left corner and top-right corner's location +inst_name_location_list = [] +# Loop through all instances +for inst in insts: + # Get the properties + cell_name = inst.getName() + BBox = inst.getBBox() + inst_x0 = BBox.xMin() + inst_y0 = BBox.yMin() + inst_x1 = BBox.xMax() + inst_y1 = BBox.yMax() + inst_name_location_list.append([cell_name, inst_x0, inst_y0, inst_x1, inst_y1]) +return inst_name_location_list",Get the bounding box of all instances +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store the name of the instance and its bottom-left corner and top-right corner's location +inst_name_location_list = [] +# Loop through all instances +for inst in insts: + # Get the properties + cell_name = inst.getName() + BBox = inst.getBBox() + inst_x0 = BBox.xMin() + inst_y0 = BBox.yMin() + inst_x1 = BBox.xMax() + inst_y1 = BBox.yMax() + inst_name_location_list.append([cell_name, inst_x0, inst_y0, inst_x1, inst_y1]) +return inst_name_location_list","How to get a list of lists, with each inner list containing the name, the bottom-left corner, and the top-right corner locations of each instance?" +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store the name of the instance and its bottom-left corner and top-right corner's location +inst_name_location_list = [] +# Loop through all instances +for inst in insts: + # Get the properties + cell_name = inst.getName() + BBox = inst.getBBox() + inst_x0 = BBox.xMin() + inst_y0 = BBox.yMin() + inst_x1 = BBox.xMax() + inst_y1 = BBox.yMax() + inst_name_location_list.append([cell_name, inst_x0, inst_y0, inst_x1, inst_y1]) +return inst_name_location_list","Show me how I can get a list of lists, with each inner list containing the name, the bottom-left corner, and the top-right corner locations of each instance." +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create an empty list to store all cell_name-library_cell_name pair +inst_name_libcell_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this instance + master_cell = inst.getMaster() + # Get the master name (library cell name) of this instance + master_name = master_cell.getName() + # Append them into a list + inst_name_libcell_list.append([cell_name, master_name]) +return inst_name_libcell_list",Get the liberty cell type for all instance +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create an empty list to store all cell_name-library_cell_name pair +inst_name_libcell_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this instance + master_cell = inst.getMaster() + # Get the master name (library cell name) of this instance + master_name = master_cell.getName() + # Append them into a list + inst_name_libcell_list.append([cell_name, master_name]) +return inst_name_libcell_list",Show me how I can get the liberty cell type for all instance in a list +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create a list to store the result +inst_name_macro_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this cell + master_cell = inst.getMaster() + # Check is the cell is a macro + is_macro = 1 if master_cell.isBlock() else 0 + # Append the result + inst_name_macro_list.append([cell_name, is_macro]) +return inst_name_macro_list",check if an instance is a macro in the design +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create an empty list to store all cell_name-library_cell_name pair +inst_name_libcell_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this instance + master_cell = inst.getMaster() + # Get the master name (library cell name) of this instance + master_name = master_cell.getName() + # Append them into a list + inst_name_libcell_list.append([cell_name, master_name]) +return inst_name_libcell_list",How can I get the liberty cell type for all instance in a list? +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create a list to store the result +inst_name_macro_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this cell + master_cell = inst.getMaster() + # Check is the cell is a macro + is_macro = 1 if master_cell.isBlock() else 0 + # Append the result + inst_name_macro_list.append([cell_name, is_macro]) +return inst_name_macro_list",How can I identify if a cell is a macro? +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create a list to store the result +inst_name_macro_list = [] +# Loop through all instances +for inst in insts: + # Get the name of the cell + cell_name = inst.getName() + # Get the master of this cell + master_cell = inst.getMaster() + # Check is the cell is a macro + is_macro = 1 if master_cell.isBlock() else 0 + # Append the result + inst_name_macro_list.append([cell_name, is_macro]) +return inst_name_macro_list","Write a script to separate standard cells and macros in the design, show the result in a list." +"# Get the design block +block = ord.get_db_block() +# Get every instance +insts = block.getInsts() +# Create a list to store the result +pin_name_location_list = [] +# Loop through all instances +for inst in insts: + # Get all pins of this cell + inst_ITerms = inst.getITerms() + # Loop through all pins + for ITerm in inst_ITerms: + # Get the pin's name defines in the lef file through MTerm + MTerm_name = inst_ITerm.getMTerm().getName() + # Get the name of the cell this pin belongs to. + inst_name = inst_ITerm.getInst().getName() + # Concat the two strings + pin_name = ""{}/{}"".format(inst_name, MTerm_name) + # Get the location of the pin in the layout + pin_loc = ITerm.getAvgXY() + if pin_loc[0]: + pin_name_location_list.append([pin_name, pin_loc[0], pin_loc[1]]) + else: + pin_name_location_list.append([pin_name, -1, -1]) +return pin_name_location_list",Get the location of all pins +"# Get the DB +db = ord.get_db() +# Get all libraries read into the DB +libs = db.getLibs() +# Create a list to store every library cell's name +libcell_name_list = [] +# Loop through all libraries +for lib in libs: + # Get all library cells in this library + lib_masters = lib.getMasters() + # Loop through all library cells + for master in lib_masters: + # Get the name and append it to the list + libcell_name = master.getName() + libcell_name_list.append(libcell_name) +return libcell_name_list",Get the name of every liberty cell diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.xlsx new file mode 100644 index 0000000..d14799c Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/DB/query.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.csv new file mode 100644 index 0000000..9b4e64a --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.csv @@ -0,0 +1,95221 @@ +code,prompt +"# Get the defined top layer of the IO pin placer + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Return the top layer +return iop.getTopLayer()",Get the defined top layer of the IO pin placer +"# Get the corner avoidance, number of slots and HPWL report of the IO pin placer + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Construct the output string with corner avoidance, HPWL report, and number of slots +output_string = ""Corner Avoidance: {}\nHPWL Report: {}\nNumber of slots: {}"".format( + parameters.getCornerAvoidance(), + parameters.getReportHPWL(), + parameters.getNumSlots() +) + +# Return the output string +return output_string","Get the corner avoidance, number of slots and HPWL report of the IO pin placer" +"# Get the vertical and horizontal length of the setting of the IO pin placer + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Return the vertical and horizontal length +return (parameters.getVerticalLength(), parameters.getHorizontalLength())",Get the vertical and horizontal length of the setting of the IO pin placer +"# Get the minimum distance setting of the IO pin placer and set it to 100 if it is 0 + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Set the minimum distance to 100 if it's 0 +min_dist = parameters.getMinDistance() +if min_dist == 0: + parameters.setMinDistance(100) + +# Set min distance in tracks +parameters.setMinDistanceInTracks(True) + +# Return the minimum distance +return min_dist",Get the minimum distance setting of the IO pin placer and set it to 100 if it is 0 +"# Change the setting of horizontal and vertical length of thr IO pin placer to 100 + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Set vertical and horizontal length to 100 +parameters.setVerticalLength(100) +parameters.setHorizontalLength(100)",Change the setting of horizontal and vertical length of thr IO pin placer to 100 +"# Adjust the setting of vertical length of the IO pin placer to 100 + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Set vertical length to 100 +parameters.setVerticalLength(100)",Adjust the setting of vertical length of the IO pin placer to 100 +"# Check if the annealing debug mode is on for the IO pin placer and print the configs of the IO pin placer + +# Get the IO Placer object of the design +io_placer = design.getIOPlacer() + +# Print the configurations of the IO placer +io_placer.printConfig() + +# Return whether the annealing debug is on +return io_placer.isAnnealingDebugOn()",Check if the annealing debug mode is on for the IO pin placer and print the configs of the IO pin placer +"# Get the number of DRVs, cloud size and set the could size to 500 from the detailed router + +# Get the Triton Route object of the design +triton_route = design.getTritonRoute() + +# Get the number of DRVs +num_drvs = triton_route.getNumDRVs() + +# Set the cloud size to 500 +cloud_size = triton_route.setCloudSize(500) + +# Return the number of DRVs and cloud size +return (num_drvs, cloud_size)","Get the number of DRVs, cloud size and set the could size to 500 from the detailed router" +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +libFiles = libDir.glob(""*.lib"") +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +design = Design(tech)",How can I read .lib files into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +lefDir = Path(""lef_path"") +lefFiles = lefDir.glob('*.lef') +# Modify the technology file postfix for other naming convention +techLefFiles = lefDir.glob(""*.tech.lef"") +# Read library files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech)",How can I read .lef files into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path(""design_path"") +design_file_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" +verilogFile = designDir/str(design_file_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name)",Show me the way to read the Verilog file into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"")","If the clock prot is called clk_i, how can I set the design clock period to 50 nanoseconds?" +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 10 um +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()","Show me the piece of code to perform floorplanning using a utilization rate of 50% and an aspect ratio of 0.66, and set the spacing between the core and the die to 10 microns" +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(118) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M6 and M7 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M6"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode)",How can I place I/O pins of the design block on M6 and M7 layers? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset()",How can I perform global placement? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Global Placement +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement +# In OpenROAD, global placement should be performed before macro placement +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl()",Place the macros onto the design block +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)",Perform detailed placement in OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Clock Tree Synthesis +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)",Show me how I can perform CTS in OpenROAD +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Add Filler Cells +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix)",Add filler cells on the design block +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power distribution network + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()",Show me how I can construct power distribution network in OpenROAD +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()",Show me how I can build power distribution network if my design has macros +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1""))",How can I perform IR drop analysis on the M1 layer where the pins are located? +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +design.evalTclString(""report_power"")","Report the switching power, internal power and leakage power of the design" +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Global Routing +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True)",Perform global routing in OpenROAD +"from openroad import Tech, Design +from pathlib import Path +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Detailed Routing +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main()",Perform detailed routing in OpenROAD +"from openroad import Design, Tech +import openroad as ord + +tech = Tech() +# Read the files into Openroad +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +db = ord.get_db() +libs = db.getLibs() +site_name = """" +for lib in libs: + sites = lib.getSites() + if len(sites) == 0: + continue + else: + site_name = sites[0].getName() + break +site = floorplan.findSite(site_name) +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()",How can I automatically search for the name of the site and use that for floorplanning? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Clock Tree Synthesis +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)",Show me how I can perform clock tree synthesis in OpenROAD +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7 and Metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, also set the width and spacing to 4 and 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, also set the width and spacing to 4 and 4 microns. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 micronsas well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 70,70. And set the bottom-left corner of the core as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 2 and 2 microns, and for the power rings on Metal8, also set the width and spacing to 2 and 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, set the width and spacing to 4 and 4 micronsas well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 70,70. And set the bottom-left corner of the core as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 70,70. And set the bottom-left corner of the core as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, also set the width and spacing to 4 and 4 microns. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, also set the width and spacing to 4 and 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 micronsas well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on metal8 and metal9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(13) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on Metal8 and Metal9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.40, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7 and Metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.50, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, also set the width and spacing to 2 and 2 microns. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.35, and set the spacing between die and core as 14 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 2 and 2 microns, and for the power rings on Metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 5 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.60, and set the spacing between die and core as 12 microns. After that, place the IO pins on metal7 and metal8. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 4 and 4 microns, and for the power rings on metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplanning and set the floorplan utilization as 0.45, and set the spacing between die and core as 10 microns. After that, place the IO pins on Metal7 and Metal8. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8, set the width and spacing to 5 and 5 microns, and for the power rings on Metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal2 grid, the Metal4 grid, and the Metal8 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal2 grid, Metal4 grid, and Metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal8 and Metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 microns,12 microns, and the top-right corner as 43 microns,42 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7, set the width and spacing to 5 and 5 microns, and for the power rings on Metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 microns,15 microns, and the top-right corner as 55 microns,35 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 microns,5 microns, and the top-right corner as 20 microns,25 microns. Meanwhile make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 70,70. And set the bottom-left corner of the core as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 microns,32 microns, and the top-right corner as 55 microns,60 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 2 and 2 microns, and for the power rings on Metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# nMacro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 microns,10 microns, and the top-right corner as 30 microns,40 microns. And place each macro at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8, set the width and spacing to 5 and 5 microns, and for the power rings on metal9, set the width and spacing to 5 and 5 microns as well. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 2 and set the spacing to 2 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal2 grid, the metal4 grid, and the metal8 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal2 grid, metal4 grid, and metal8 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal8 and metal9, set the width to 5 and set the spacing to 5 microns. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times thethe pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""Metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""Metal9"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform CTS with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal8 and Metal9, and have power grids on Metal1 , Metal2, and Metal4 for standard cells and macros. For the power rings on Metal8 and Metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on Metal5 and Metal6. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal8 and metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m2 = design.getTech().getDB().getTech().findLayer(""metal2"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +m9 = design.getTech().getDB().getTech().findLayer(""metal9"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m8, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m9, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m2, width = m2.getMinWidth(), + spacing = m2.getSpacing(), pitch = m2.getPitch(), offset = m2.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m8, width = m8.getMinWidth(), + spacing = m8.getSpacing(), pitch = m8.getPitch(), offset = m8.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m2, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m2, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m8, layer1 = m9, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal8 and metal9, and have power grids on metal1 , metal2, and metal4 for standard cells and macros. For the power rings on metal8 and metal9, set the width to 4 and set the spacing to 4 microns. If there are macros, build power grids for macros on metal5 and metal6. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal8 and Metal9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7 and Metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. Set the width of the Metal1 grid, the Metal4 grid, and the Metal7 grid using the minimum value from the technology file. Then set the spacing of the Metal1 grid, Metal4 grid, and Metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on Metal7 and Metal8, set the width to 5 and set the spacing to 5. If there are macros, build power rings and grids for macros on Metal5 and Metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on Metal5 and Metal6, set the width to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7 and Metal8, set the width to 4 and set the spacing to 4 microns. If there are macros, build power rings and grids for macros on Metal5 and Metal6 and set the width for the power ring on Metal5 and Metal6 to 2 microns and set the spacing to 2 microns. And if there are parallel grids, set the pitch of the via between two grids to 2 microns. In the routing stage, route the design from Metal1 to Metal6. In the end, perform IR drop analysis on Metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7 and metal8, set the width to 2 and set the spacing to 2 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 and set the width for the power ring on metal5 and metal6 to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the standard cells and the macros. Place each macro at least 5 microns away from each other, and set a halo region around each macro as 5 microns. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7 and metal8, set the width to 5 and set the spacing to 5 microns. If there are macros, build power rings and grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. However, for the power ring on metal5 and metal6, set the width to 1.5 microns and set the spacing to 1.5 microns. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. After PDN construction, get the IR drop analysis result on metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,40. And set the bottom-left corner of the core as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Macro_core_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Macro_core_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""Metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""Metal6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""Metal1"" +params.topRoutingLayer = ""Metal6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 70,70. And set the bottom-left corner of the core as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 microns, and the y-axis as0. After the placement stage, perform clock tree synthesis with using bufferx1 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 4 and 4 microns, and for the power rings on Metal8, set the width and spacing to 4 and 4 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After constructing power grids, perform IR drop analysis on Metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from Metal1 to Metal6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +# Report Power +ndesign.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, also set the width and spacing to 2 and 2 microns. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. After constructing power grids, perform IR drop analysis on metal1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from metal1 to metal7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""metal1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 microns, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. In the end, perform IR drop analysis on metal1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Instance_pdn_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Instance_pdn_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 60,50. And set the bottom-left corner of the core as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. Set the width of the metal1 grid, the metal4 grid, and the metal7 grid using the minimum value from the technology file. Then set the spacing of the metal1 grid, metal4 grid, and metal7 grid using the minimum value from the technology file as well, but set the pitch of those grids using two times the minimum value from the technology file. Set the offset using the default value. For the power rings on metal7, set the width and spacing to 5 and 5 microns, and for the power rings on metal8, set the width and spacing to 5 and 5 microns as well. If there are macros, build power grids for macros on metal5 and metal6 with using minimum values for width and spacing from the technology file for power grids, and use two times the pitch value from the technology file for macro's power grids. And if there are parallel grids, set the pitch of the via between two grids to 0 microns. In the routing stage, route the design from metal1 to metal7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLCELL_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""Core_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") +grid = pdngen.findGrid(""Core_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 45,45. And set the bottom-left corner of the core as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on metal7 and metal8, and have power grids on metal1 and metal4 for standard cells and macros. For the power rings on metal7, set the width and spacing to 2 and 2 microns, and for the power rings on metal8, set the width and spacing to 2 and 2 micronsas well. If there are macros, build power grids for macros on metal5 and metal6 and set the pitch of the via between two grids to 0 microns. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on Metal7 and Metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""Metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""Metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer Metal4 (usually Metal4) + layer = design.getTech().getDB().getTech().findLayer(""Metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""bufferx1"") +cts.setRootBuffer(""bufferx1"") +cts.setSinkBuffer(""bufferx1"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""FILLER_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +halo = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""_core_"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""Metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""Metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""Metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""Metal8"") +grid = pdngen.findGrid(""_core_"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on Metal1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = m1.getMinWidth(), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = m4.getMinWidth(), + spacing = m4.getSpacing(), pitch = m4.getPitch(), offset = m4.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = m7.getMinWidth(), + spacing = m7.getSpacing(), pitch = m7.getPitch(), offset = m7.getOffset(), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""Metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""Metal6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = f""Core_macro_grid_{i}"", + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(f""Core_macro_grid_{i}"") + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = m5.getMinWidth(), + spacing = m5.getSpacing(), pitch = m5.getPitch(), offset = m5.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = m6.getMinWidth(), + spacing = m6.getSpacing(), pitch = m6.getPitch(), offset = m6.getOffset(), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""Metal2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as1. After placement, do CTS and use bufferx1 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on Metal7 and Metal8, and have power grids on Metal1 and Metal4 for standard cells and macros. For the power rings on Metal7, set the width and spacing to 2 and 2 microns, and for the power rings on Metal8, set the width and spacing to 2 and 2 microns as well. If there are macros, build power grids for macros on Metal5 and Metal6 and set the pitch of the via between two grids to 2 microns. After PDN construction, get the IR drop analysis result on Metal1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on metal7 and metal8 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer metal4 (usually metal4) + layer = design.getTech().getDB().getTech().findLayer(""metal4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 nanoseconds. Then perform floorplan and set the bottom-left corner of the die as 0,0 and the top-right corner as 40,60. And set the bottom-left corner of the core as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 microns to each other, and set a halo region around each macro as 5 microns. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 microns, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +libFiles = libDir.glob(""*.lib"") +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +design = Design(tech)",Show me how I can read .lib files into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +libFiles = libDir.glob(""*.lib"") +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +design = Design(tech)",Write a piece of code to read .lib files into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +lefDir = Path(""lef_path"") +lefFiles = lefDir.glob('*.lef') +# Modify the technology file postfix for other naming convention +techLefFiles = lefDir.glob(""*.tech.lef"") +# Read library files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech)",Show me how I can read .lef files into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +lefDir = Path(""lef_path"") +lefFiles = lefDir.glob('*.lef') +# Modify the technology file postfix for other naming convention +techLefFiles = lefDir.glob(""*.tech.lef"") +# Read library files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech)",Write a piece of code to read .lef files into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path(""design_path"") +design_file_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" +verilogFile = designDir/str(design_file_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name)",Show me how I can read the Verilog file into OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path(""design_path"") +design_file_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" +verilogFile = designDir/str(design_file_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name)",How can I read the Verilog file into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path(""design_path"") +design_file_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" +verilogFile = designDir/str(design_file_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name)",Write a piece of code to read the Verilog file into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"")","If the clock prot is called clk_i, how can I set the design clock period to 50 nanoseconds?" +"from openroad import Design, Tech +import openroad as ord + +tech = Tech() +# Read the files into Openroad +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +db = ord.get_db() +libs = db.getLibs() +site_name = """" +for lib in libs: + sites = lib.getSites() + if len(sites) == 0: + continue + else: + site_name = sites[0].getName() + break +site = floorplan.findSite(site_name) +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()",Show me the code that automatically searches for the name of the site and uses that for floorplanning. +"from openroad import Design, Tech +import openroad as ord + +tech = Tech() +# Read the files into Openroad +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +db = ord.get_db() +libs = db.getLibs() +site_name = """" +for lib in libs: + sites = lib.getSites() + if len(sites) == 0: + continue + else: + site_name = sites[0].getName() + break +site = floorplan.findSite(site_name) +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()","If I don't know the name of the site defined in the library, how can I perform floorplanning then?" +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.xlsx new file mode 100644 index 0000000..4549a5d Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Prompt-Script/Flow/flow.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.csv new file mode 100644 index 0000000..77871e3 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.csv @@ -0,0 +1,224 @@ +Prompts,Answers +Brief me on OpenROAD Flow?,"OpenROAD-flow-scripts (ORFS) is a fully autonomous, RTL-GDSII flow for rapid architecture and design space exploration, early prediction of QoR, and detailed physical design implementation. However, ORFS also enables manual intervention for finer user control of individual flow stages through Tcl commands and Python APIs." +What is OpenROAD Flow and its benefits?,"OpenROAD-flow-scripts (ORFS) is a fully autonomous, RTL-GDSII flow for rapid architecture and design space exploration, early prediction of QoR, and detailed physical design implementation. However, ORFS also enables manual intervention for finer user control of individual flow stages through Tcl commands and Python APIs." +Brief me on OpenROAD Flow?,"OpenROAD-flow-scripts offer a comprehensive, autonomous RTL-GDSII flow for rapid design exploration and physical design, allowing for manual intervention at stages through Tcl commands and Python APIs for greater control." +"I'm trying to port ORFS to a TSMC process. During the detailed route step, I get a lot of DRT-0073 errors. Utilization is set to 20% at the beginning of the P&R flow and it is a pretty simple design. Give me some tips about what to look into? +I have tried to run the pin_access command directly but the -verbose parameter does not seem to work as I don't get any more information","You can try the developer debugs to get a sense of what is going on. Put detailed_route_debug -pa -pa_markers -pin _3504_:A1 before you call detailed_route and run it in the GUI. It will stop at the pin and show you how it is trying to access it and any associated drc markers. You click the continue button to see the various steps. Hopefully, that gives you an idea as to what is going on. The other option is a support contract with precisioninno.com where we can help under NDA. +" +I'm encountering DRT-0073 errors during detailed routing in ORFS; any advice?,"You can try the developer debugs to get a sense of what is going on. Put detailed_route_debug -pa -pa_markers -pin _3504_:A1 before you call detailed_route and run it in the GUI. It will stop at the pin and show you how it is trying to access it and any associated drc markers. You click the continue button to see the various steps. Hopefully, that gives you an idea as to what is going on. The other option is a support contract with precisioninno.com where we can help under NDA. +" +"I'm trying to port ORFS to a TSMC process. During the detailed route step, I get a lot of DRT-0073 errors. Utilization is set to 20% at the beginning of the P&R flow and it is a pretty simple design. Give me some tips about what to look into? +I have tried to run the pin_access command directly but the -verbose parameter does not seem to work as I don't get any more information","Developer debug options in OpenROAD can give insights into detailed routing processes, offering visual debug aids in the GUI and the option for NDA-supported assistance from precisioninno.com." +What does the following argument do in the build command of ORFS: -o or —local?,"The argument, o or —local, builds locally instead of building a Docker image." +How does the -o or —local argument function in the build command of ORFS?,"The argument, o or —local, builds locally instead of building a Docker image." +What does the following argument do in the build command of ORFS: -o or —local?,The -o or --local argument opts for a local build over Docker. +What operation does the -l or --latest argument perform in the build command of ORFS?,The -l or --latest argument specifies to use of the head of branch –or_branch or ‘master’ by default for tools/OpenROAD. +What is accomplished by the -l or --latest argument in the build command of ORFS?,The -l or --latest argument specifies to use of the head of branch –or_branch or ‘master’ by default for tools/OpenROAD. +What operation does the -l or --latest argument perform in the build command of ORFS?,"The -l or --latest argument chooses the latest branch head for tools/OpenROAD, defaulting to master." +How is this argument utilized in the build command of ORFS: --or_branch BRANCH_NAME?,The -or_branch BRANCH_NAME argument stipulates the use of the head of branch BRANCH for tools/OpenROAD. +How is the --or_branch BRANCH_NAME argument used in the build command of ORFS?,The -or_branch BRANCH_NAME argument stipulates the use of the head of branch BRANCH for tools/OpenROAD. +How is this argument utilized in the build command of ORFS: --or_branch BRANCH_NAME?,The -or_branch BRANCH_NAME argument selects the branch head of BRANCH for tools/OpenROAD. +What role does this argument play in the build command of ORFS: --or_repo REPO_URL?, This argument enumerates to use of a fork at REPO-URL (https/ssh) for tools/OpenROAD. +What does the --or_repo REPO_URL argument specify in the build command of ORFS?, This argument enumerates to use of a fork at REPO-URL (https/ssh) for tools/OpenROAD. +What role does this argument play in the build command of ORFS: --or_repo REPO_URL?,Specifies using a tools/OpenROAD fork at a given REPO-URL. +What does the following argument do in the build command of ORFS: --no_init?,The --no_init argument prescribes skipping initializing submodules. +What does the --no_init argument accomplish in the build command of ORFS?,The --no_init argument prescribes skipping initializing submodules. +What does the following argument do in the build command of ORFS: --no_init?,The --no_init option omits submodule initialization. +How does the following argument function in the build command of ORFS: -t N or --threads N?,The -t N or --threads N argument stipulates the use of N cpus when compiling software. +What does the -t N or --threads N argument control in the build command of ORFS?,The -t N or --threads N argument stipulates the use of N cpus when compiling software. +How does the following argument function in the build command of ORFS: -t N or --threads N?,The -t N or --threads N argument utilizes N CPUs for software compilation. +What is the purpose of the following argument in the build command of ORFS: -n or --nice?,"The -n or --nice flag in the build script instructs the build script to set all jobs to the maximim Unix ""niceness"". Niceness determines how much the operating system prefers to schedule process. The purpose of setting this flag is to ensure that a system is not overwhelmed by using all available processing primarily of the build jobs. The build will use all CPUs by default unless --threads is also given, then N threads are used instead." +What is the purpose of the -n or --nice argument in the build command of ORFS?,"The -n or --nice flag in the build script instructs the build script to set all jobs to the maximim Unix ""niceness"". Niceness determines how much the operating system prefers to schedule process. The purpose of setting this flag is to ensure that a system is not overwhelmed by using all available processing primarily of the build jobs. The build will use all CPUs by default unless --threads is also given, then N threads are used instead." +What is the purpose of the following argument in the build command of ORFS: -n or --nice?,"The build script's -n or --nice flag sets all jobs to the maximum Unix ""niceness"" level. This determines the priority with which the operating system schedules processes. The aim is to prevent system overload by allocating all processing power primarily to the build jobs. Without specifying otherwise, the build utilizes all CPUs, but specifying --threads allows for the use of a fixed number of threads." +What does the following argument do in the build command of ORFS: —yosys-args-overwrite?,This argument states to not use default flags set by this scrip during Yosys compilation. +What does the --yosys-args-overwrite argument modify in the build command of ORFS?,This argument states to not use default flags set by this scrip during Yosys compilation. +What does the following argument do in the build command of ORFS: —yosys-args-overwrite?,This parameter instructs the script to ignore the default flags during Yosys compilation. +What is the purpose of the following argument in the build command of ORFS: —yosys-args STRING?,The '—yosys-args STRING' argument adds additional compilation flags for Yosys compilation. +How does the --yosys-args STRING argument customize the build process in ORFS?,The '—yosys-args STRING' argument adds additional compilation flags for Yosys compilation. +What is the purpose of the following argument in the build command of ORFS: —yosys-args STRING?,The '--yosys-args STRING' option allows for the inclusion of extra flags in Yosys compilations. +What function does the following argument serve in the build command of ORFS: —openroad-args-overwrite?,The '—openroad-args-overwrite' argument specifies to not use default flags set by this script during OpenROAD app compilation. +What modification does the --openroad-args-overwrite argument make in the build command of ORFS?,The '—openroad-args-overwrite' argument specifies to not use default flags set by this script during OpenROAD app compilation. +What function does the following argument serve in the build command of ORFS: —openroad-args-overwrite?,The '--openroad-args-overwrite' option commands the script not to apply its default flags during OpenROAD app compilations. +What does the following argument do in the build command of ORFS: —openroad-args STRING?,The '—openroad-args STRING' argument adds aditional compilation flags for OpenROAD app compilation. +How does the --openroad-args STRING argument alter the build process in ORFS?,The '—openroad-args STRING' argument adds aditional compilation flags for OpenROAD app compilation. +What does the following argument do in the build command of ORFS: —openroad-args STRING?,The '--openroad-args STRING' option introduces additional flags for compiling the OpenROAD app. +What is the purpose of the following argument in the build command of ORFS: —lsoracle-enable?,This argument initiates compiling LSOracle since it is disabled by default as it is not currently used on the flow. +What is the function of the --lsoracle-enable argument in the build command of ORFS?,This argument initiates compiling LSOracle since it is disabled by default as it is not currently used on the flow. +What is the purpose of the following argument in the build command of ORFS: —lsoracle-enable?,"Activates the compilation of LSOracle, which is off by default as it's not part of the current workflow." +What does the following argument do in the build command of ORFS: —lsoracle-args-overwrite?,The '—lsoracle-args-overwrite' argument stipulates not to use default flags set by this script during LSOracle compilation. +What does the --lsoracle-args-overwrite argument change in the build command of ORFS?,The '—lsoracle-args-overwrite' argument stipulates not to use default flags set by this script during LSOracle compilation. +What does the following argument do in the build command of ORFS: —lsoracle-args-overwrite?,The '--lsoracle-args-overwrite' command directs the script to bypass default flags for LSOracle compilations. +What does the following argument achieve in the build command of ORFS: —lsoracle-args STRING?,This argument adds aditional compilation flags for LSOracle compilation. +How does the --lsoracle-args STRING argument customize the ORFS build process?,This argument adds aditional compilation flags for LSOracle compilation. +What does the following argument achieve in the build command of ORFS: —lsoracle-args STRING?,This command introduces extra compilation flags for LSOracle. +What function does the following argument serve in the build command of ORFS: —install-path PATH?,The '—install-path PATH' delineates the path to install tools. Default is ${INSTALL_PATH}. +What does the --install-path PATH argument specify in the build command of ORFS?,The '—install-path PATH' delineates the path to install tools. Default is ${INSTALL_PATH}. +What function does the following argument serve in the build command of ORFS: —install-path PATH?,"The '--install-path PATH' option specifies the installation directory for tools, with ${INSTALL_PATH} as the default." +What does the following argument do in the build command of ORFS: —clean?,The '—clean' argument calls the git clean command interactively before compiling. It is useful to remove old build files. +What is achieved by the --clean argument in the build command of ORFS?,The '—clean' argument calls the git clean command interactively before compiling. It is useful to remove old build files. +What does the following argument do in the build command of ORFS: —clean?,"The '--clean' argument triggers an interactive git clean command before compiling, helping remove outdated build files." +What does the following argument do in the build command of ORFS: —clean-force?,This '—clean-force' argument will call git clean before compiling but WARNING: this option will not ask for confirmation. It is useful to remove old build files. +How does the --clean-force argument function in the build command of ORFS?,This '—clean-force' argument will call git clean before compiling but WARNING: this option will not ask for confirmation. It is useful to remove old build files. +What does the following argument do in the build command of ORFS: —clean-force?,"The '--clean-force' command enforces a git clean operation before compilation without seeking user confirmation, aiding in the deletion of old build files." +What function does the following argument serve in the build command of ORFS: -c or --copy-platforms?,This argument is only applicable to docker builds. It is used to copy platforms inside the docker image. +What does the -c or --copy-platforms argument do in the build command of ORFS?,This argument is only applicable to docker builds. It is used to copy platforms inside the docker image. +What function does the following argument serve in the build command of ORFS: -c or --copy-platforms?,"This command is tailored for docker builds, enabling the copying of platforms into the docker image." +What does the following argument do in the build command of ORFS: —docker-args-overwrite?,The ' —docker-args-overwrite' argument is only applicable for docker builds. They specify to not use default flags set by this script for Docker builds. +What modification does the --docker-args-overwrite argument make in the build command of ORFS?,The ' —docker-args-overwrite' argument is only applicable for docker builds. They specify to not use default flags set by this script for Docker builds. +What does the following argument do in the build command of ORFS: —docker-args-overwrite?,"The '--docker-args-overwrite' command is designated for docker builds, instructing not to use the script's default Docker build flags." +What does the following argument do in the build command of ORFS: —docker-args STRING?,This argument is only applicable to docker builds. It is used to add additional compilation flags for the Docker build. +How does the --docker-args STRING argument customize the ORFS build process?,This argument is only applicable to docker builds. It is used to add additional compilation flags for the Docker build. +What does the following argument do in the build command of ORFS: —docker-args STRING?,"This command, specific to docker builds, allows adding extra compilation flags for Docker builds." +"What does the following Synthesis variable, SYNTH_HIERARCHICAL do?","The variable SYNTH_HIERARCHICAL enables synthesis hierarchically, otherwise considered flat synthesis." +What does the SYNTH_HIERARCHICAL variable in Synthesis control?,"The variable SYNTH_HIERARCHICAL enables synthesis hierarchically, otherwise considered flat synthesis." +"What does the following Synthesis variable, SYNTH_HIERARCHICAL do?",SYNTH_HIERARCHICAL toggles between hierarchical and flat synthesis. +"What does the following Synthesis variable, LATCH_MAP_FILE do?",LATCH_MAP_FILE variable specifies the list of latches treated as a black box by Yosys. +What is the purpose of the LATCH_MAP_FILE variable in Synthesis?,LATCH_MAP_FILE variable specifies the list of latches treated as a black box by Yosys. +"What does the following Synthesis variable, LATCH_MAP_FILE do?",LATCH_MAP_FILE lists latches considered as black boxes by Yosys. +"What does the following Synthesis variable, CLKGATE_MAP_FILE do?",This variable specifies a list of cells for the gating clock treated as a black box by Yosys. +How does the CLKGATE_MAP_FILE variable in Synthesis function?,This variable specifies a list of cells for the gating clock treated as a black box by Yosys. +"What does the following Synthesis variable, CLKGATE_MAP_FILE do?",Specifies cells to treat as black boxes for clock gating in Yosys. +"Can you explain the usage of this Synthesis variable, ADDER_MAP_FILE?",List of adders treated as a black box by Yosys. +What does the ADDER_MAP_FILE variable in Synthesis specify?,List of adders treated as a black box by Yosys. +"Can you explain the usage of this Synthesis variable, ADDER_MAP_FILE?",Lists adders treated as black boxes by Yosys. +"What does the following Synthesis variable, TIEHI_CELL_AND_PORT do?","The variable, TIEHI_CELL_AND_PORT is used to tie high cells used in Yosys synthesis to replace a logical 1 in the Netlist." +What does the TIEHI_CELL_AND_PORT variable in Synthesis define?,"The variable, TIEHI_CELL_AND_PORT is used to tie high cells used in Yosys synthesis to replace a logical 1 in the Netlist." +"What does the following Synthesis variable, TIEHI_CELL_AND_PORT do?",TIEHI_CELL_AND_PORT identifies high tie cells used in Yosys synthesis to replace logical 1 in the Netlist. +"What does the following Synthesis variable, TIELO_CELL_AND_PORT do?",This variable is used to tie low cells used in Yosys synthesis to replace a logical 0 in the Netlist. +What does the TIELO_CELL_AND_PORT variable in Synthesis indicate?,This variable is used to tie low cells used in Yosys synthesis to replace a logical 0 in the Netlist. +"What does the following Synthesis variable, TIELO_CELL_AND_PORT do?",Defines low tie cells used in Yosys synthesis to replace logical 0 in the Netlist. +"What does the following Synthesis variable, MIN_BUF_CELL_AND_PORTS do?",The MIN_BUF_CELL_AND_PORTS variable is used to insert a buffer cell to pass through wires. Used in synthesis. +How does the MIN_BUF_CELL_AND_PORTS variable in Synthesis operate?,The MIN_BUF_CELL_AND_PORTS variable is used to insert a buffer cell to pass through wires. Used in synthesis. +"What does the following Synthesis variable, MIN_BUF_CELL_AND_PORTS do?","MIN_BUF_CELL_AND_PORTS inserts a buffer cell for wire pass-through, used in synthesis." +"What does the following Synthesis variable, ABC_CLOCK_PERIOD_IN_PS do?","The variable, ABC_CLOCK_PERIOD_IN_PS is used to specify the clock period to be used by STA during synthesis. Default value read from constraint.sdc." +What does the ABC_CLOCK_PERIOD_IN_PS variable in Synthesis determine?,"The variable, ABC_CLOCK_PERIOD_IN_PS is used to specify the clock period to be used by STA during synthesis. Default value read from constraint.sdc." +"What does the following Synthesis variable, ABC_CLOCK_PERIOD_IN_PS do?","ABC_CLOCK_PERIOD_IN_PS sets the clock period for STA during synthesis, with a default from constraint.sdc." +"What does the following Synthesis variable, ABC_DRIVER_CELL do?",Default driver cell used during ABC synthesis. +What does the ABC_DRIVER_CELL variable in Synthesis specify?,Default driver cell used during ABC synthesis. +"What does the following Synthesis variable, ABC_DRIVER_CELL do?",Specifies the default driver cell for ABC synthesis. +"What does the following Synthesis variable, ABC_LOAD_IN_FF do?","During synthesis, the set_load value specified by this, ABC_LOAD_IN_FF variable is used." +What does the ABC_LOAD_IN_FF variable in Synthesis imply?,"During synthesis, the set_load value specified by this, ABC_LOAD_IN_FF variable is used." +"What does the following Synthesis variable, ABC_LOAD_IN_FF do?",ABC_LOAD_IN_FF sets the load value during synthesis. +"What does the following Synthesis variable, MAX_UNGROUP_SIZE do?","For hierarchical synthesis, this variable ungroups modules of the size given by this variable." +What does the MAX_UNGROUP_SIZE variable in Synthesis control?,"For hierarchical synthesis, this variable ungroups modules of the size given by this variable." +"What does the following Synthesis variable, MAX_UNGROUP_SIZE do?","For hierarchical synthesis, ungroups modules based on specified size." +"Tell me about the Floorplan variable, FLOORPLAN_DEF?",FLOORPLAN_DEF is used to specify the use of the DEF file to initialize floorplan. +Can you explain the FLOORPLAN_DEF variable in Floorplan?,FLOORPLAN_DEF is used to specify the use of the DEF file to initialize floorplan. +"Tell me about the Floorplan variable, FLOORPLAN_DEF?",FLOORPLAN_DEF uses a DEF file to initialize the floorplan. +"Elaborate on the Floorplan variable, PLACE_SITE?",Placement site for core cells defined in the technology LEF file. +What is the role of the PLACE_SITE variable in Floorplan?,Placement site for core cells defined in the technology LEF file. +"Elaborate on the Floorplan variable, PLACE_SITE?",Defines the placement site for core cells in the technology LEF file. +"Describe the use this Floorplan variable, TAPCELL_TCL?",TAPCELL_TCL specifies the path to the Endcap and Welltie cells file. +How does the TAPCELL_TCL variable in Floorplan function?,TAPCELL_TCL specifies the path to the Endcap and Welltie cells file. +"Describe the use this Floorplan variable, TAPCELL_TCL?",TAPCELL_TCL points to the Endcap and Welltie cells file. +"What is the function of the Floorplan variable, RTLMP_FLOW?","This variable, RTLMP_FLOW enables the Hierarchical RTLMP flow. By default it is disabled." +What does the RTLMP_FLOW variable in Floorplan control?,"This variable, RTLMP_FLOW enables the Hierarchical RTLMP flow. By default it is disabled." +"What is the function of the Floorplan variable, RTLMP_FLOW?","RTLMP_FLOW toggles the Hierarchical RTLMP flow, defaulting to off." +"Tell me about the Floorplan variable, MACRO_HALO?","MACRO_HALO specifies to keep out a distance from macro, in X and Y, to standard cell row." +Can you describe the MACRO_HALO variable in Floorplan?,"MACRO_HALO specifies to keep out a distance from macro, in X and Y, to standard cell row." +"Tell me about the Floorplan variable, MACRO_HALO?",MACRO_HALO sets the keep-out distance around macros in X and Y to standard cell rows. +"Tell me about the Floorplan variable, MACRO_PLACEMENT?",MACRO_PLACEMENT specifies the path of a file on how to place certain macros manually using read_macro_placement. +What does the MACRO_PLACEMENT variable in Floorplan specify?,MACRO_PLACEMENT specifies the path of a file on how to place certain macros manually using read_macro_placement. +"Tell me about the Floorplan variable, MACRO_PLACEMENT?",MACRO_PLACEMENT defines manual macro placement through a specified file. +"Elaborate on the Floorplan variable, MACRO_PLACEMENT_TCL?",This variable specifies the path of a TCL file on how to place certain macros manually. +How does the MACRO_PLACEMENT_TCL variable in Floorplan operate?,This variable specifies the path of a TCL file on how to place certain macros manually. +"Elaborate on the Floorplan variable, MACRO_PLACEMENT_TCL?",Specifies a TCL file for manual macro placement. +"Describe the Floorplan variable, MACRO_PLACE_HALO?",Horizontal /vertical halo around macros (microns). Used by automatic macro placement. +What does the MACRO_PLACE_HALO variable in Floorplan indicate?,Horizontal /vertical halo around macros (microns). Used by automatic macro placement. +"Describe the Floorplan variable, MACRO_PLACE_HALO?","Sets the halo around macros for automatic placement, in microns." +"Tell me about the Floorplan variable, MACRO_PLACE_CHANNEL?",Horizontal/vertical channel width between macros (microns). Used by automatic macro placement when RTLMP_FLOW is disabled. Imagine channel=10 and halo=5. Then macros must be 10 apart but standard cells must be 5 away from a macro. +What does the MACRO_PLACE_CHANNEL variable in Floorplan define?,Horizontal/vertical channel width between macros (microns). Used by automatic macro placement when RTLMP_FLOW is disabled. Imagine channel=10 and halo=5. Then macros must be 10 apart but standard cells must be 5 away from a macro. +"Tell me about the Floorplan variable, MACRO_PLACE_CHANNEL?","Determines the channel width between macros for automatic placement, in microns." +"Give me details on the Floorplan variable, MACRO_BLOCKAGE_HALO?",Blockage width overridden from default calculation. +Can you detail the MACRO_BLOCKAGE_HALO variable in Floorplan?,Blockage width overridden from default calculation. +"Give me details on the Floorplan variable, MACRO_BLOCKAGE_HALO?",Overrides the default blockage width calculation. +"Inform me about the Floorplan variable, PDN_TCL?","This variable specifies the file path which has a set of power grid policies used by pdn to be applied to the design, such as layers to use, stripe width and spacing to generate the actual metal straps." +What is the purpose of the PDN_TCL variable in Floorplan?,"This variable specifies the file path which has a set of power grid policies used by pdn to be applied to the design, such as layers to use, stripe width and spacing to generate the actual metal straps." +"Inform me about the Floorplan variable, PDN_TCL?",Specifies the file path for power grid policies used by pdn. +"Tell me about the Floorplan variable, MAKE_TRACKS.",MAKE_TRACKS variable outlines the Tcl file that defines adding routing tracks to a floorplan. +How does the MAKE_TRACKS variable in Floorplan function?,MAKE_TRACKS variable outlines the Tcl file that defines adding routing tracks to a floorplan. +"Tell me about the Floorplan variable, MAKE_TRACKS.",MAKE_TRACKS outlines a Tcl file for adding routing tracks to a floorplan. +"What is the function of the Floorplan variable, IO_PLACER_H?",The metal layer on which to place the I/O pins horizontally (top and bottom of the die). +What does the IO_PLACER_H variable in Floorplan specify?,The metal layer on which to place the I/O pins horizontally (top and bottom of the die). +"What is the function of the Floorplan variable, IO_PLACER_H?",Specifies the metal layer for horizontal I/O pin placement. +"Inform me about the Floorplan variable, IO_PLACER_V?",The metal layer on which to place the I/O pins vertically (sides of the die). +How does the IO_PLACER_V variable in Floorplan operate?,The metal layer on which to place the I/O pins vertically (sides of the die). +"Inform me about the Floorplan variable, IO_PLACER_V?",Specifies the metal layer for vertical I/O pin placement. +"Tell me about the Floorplan variable, GUI_NO_TIMING?",Skip loading timing for a faster GUI load. +What does the GUI_NO_TIMING variable in Floorplan control?,Skip loading timing for a faster GUI load. +"Tell me about the Floorplan variable, GUI_NO_TIMING?",Skips loading timing for faster GUI loading. +"Give me a description for the following ‘Placement’ tool variable, HAS_IO_CONSTRAINTS?",Skip the initial non-IO based global placement if IO constraints are present. +Can you describe the HAS_IO_CONSTRAINTS variable in the Placement tool?,Skip the initial non-IO based global placement if IO constraints are present. +"Give me a description for the following ‘Placement’ tool variable, HAS_IO_CONSTRAINTS?",Skips initial non-IO based global placement if IO constraints exist. +"Tell me about the ‘Placement’ tool variable, CELL_PAD_IN_SITES_GLOBAL_PLACEMENT?",Cell padding on both sides in site widths to ease routability during global placement. +What does the CELL_PAD_IN_SITES_GLOBAL_PLACEMENT variable in Placement do?,Cell padding on both sides in site widths to ease routability during global placement. +"Tell me about the ‘Placement’ tool variable, CELL_PAD_IN_SITES_GLOBAL_PLACEMENT?",Defines cell padding in site widths for global placement routability. +"What does this ‘Placement’ tool variable, CELL_PAD_IN_SITES_DETAIL_PLACEMENT do?",Cell padding on both sides in site widths to ease routability in detail placement. +How does the CELL_PAD_IN_SITES_DETAIL_PLACEMENT variable in Placement function?,Cell padding on both sides in site widths to ease routability in detail placement. +"What does this ‘Placement’ tool variable, CELL_PAD_IN_SITES_DETAIL_PLACEMENT do?",Defines cell padding in site widths for detail placement routability. +"Give me a description for the following ‘Placement’ tool variable, PLACE_DENSITY?",The desired placement density of cells. It reflects how spread the cells would be on the core area. 1.0 = closely dense. 0.0 = widely spread. +What does the PLACE_DENSITY variable in Placement control?,The desired placement density of cells. It reflects how spread the cells would be on the core area. 1.0 = closely dense. 0.0 = widely spread. +"Give me a description for the following ‘Placement’ tool variable, PLACE_DENSITY?",Sets the desired placement density of cells on the core area. +"What does this ‘Placement’ tool variable, PLACE_DENSITY_LB_ADDON do?",Check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists. +How does the PLACE_DENSITY_LB_ADDON variable in Placement operate?,Check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists. +"What does this ‘Placement’ tool variable, PLACE_DENSITY_LB_ADDON do?",Adjusts the lower boundary of PLACE_DENSITY with an addon if present. +"State the function of this OpenROAD ‘Placement’ tool variable, REPAIR_PDN_VIA_LAYER?",Remove power grid vias which generate DRC violations after detailed routing. +What does the REPAIR_PDN_VIA_LAYER variable in Placement specify?,Remove power grid vias which generate DRC violations after detailed routing. +"State the function of this OpenROAD ‘Placement’ tool variable, REPAIR_PDN_VIA_LAYER?",Removes power grid vias causing DRC violations after detailed routing. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GLOBAL_PLACEMENT_ARGS?",Use additional tuning parameters during global placement other than default args defined in gloabl_place.tcl. +Can you explain the GLOBAL_PLACEMENT_ARGS variable in Placement?,Use additional tuning parameters during global placement other than default args defined in gloabl_place.tcl. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GLOBAL_PLACEMENT_ARGS?",Uses additional parameters for global placement beyond default args. +"What does this OpenROAD ‘Placement’ tool variable, ENABLE_DPO do?",Enable detail placement with improve_placement feature. +What does the ENABLE_DPO variable in Placement do?,Enable detail placement with improve_placement feature. +"What does this OpenROAD ‘Placement’ tool variable, ENABLE_DPO do?",Enables detailed placement improvement. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, DPO_MAX_DISPLACEMENT?",Specifies how far an instance can be moved when optimizing. +How does the DPO_MAX_DISPLACEMENT variable in Placement function?,Specifies how far an instance can be moved when optimizing. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, DPO_MAX_DISPLACEMENT?",Limits instance movement distance during optimization. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_TIMING_DRIVEN?","In OpenROAD Flow Scripts (ORFS), the GPL_TIMING_DRIVEN variable specifies whether the global placer (gpl) should use timing driven-placement. Timing-driven placement will cause gpl to ocassionally run static timing analysis (sta) during placement in order to determine the timing on each net. gpl will then reweight the nets based on how timing-critical they are. This process improves the timing of the netlist by decreasing the distance between timing-critical cells, but it also causes an increase in gpl runtime due to running timing analysis." +What does the GPL_TIMING_DRIVEN variable in Placement control?,"In OpenROAD Flow Scripts (ORFS), the GPL_TIMING_DRIVEN variable specifies whether the global placer (gpl) should use timing driven-placement. Timing-driven placement will cause gpl to ocassionally run static timing analysis (sta) during placement in order to determine the timing on each net. gpl will then reweight the nets based on how timing-critical they are. This process improves the timing of the netlist by decreasing the distance between timing-critical cells, but it also causes an increase in gpl runtime due to running timing analysis." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_TIMING_DRIVEN?","GPL_TIMING_DRIVEN toggles timing-driven global placement, affecting gpl runtime and netlist timing." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_ROUTABILITY_DRIVEN?","In OpenROAD Flow Scripts (ORFS), the GPL_ROUTABILITY_DRIVEN variable specifies whether the global placer (gpl) should use routability driven-placement. Routability-driven placement will cause gpl to ocassionally run global routing (grt) during placement in order to determine routing congestion hotspots. gpl will then reweight the nets based on how congestion data. This process improves the routability of the netlist by spacing out cells in routing congested areas, but it also causes an increase in gpl runtime due to running global routing." +How does the GPL_ROUTABILITY_DRIVEN variable in Placement operate?,"In OpenROAD Flow Scripts (ORFS), the GPL_ROUTABILITY_DRIVEN variable specifies whether the global placer (gpl) should use routability driven-placement. Routability-driven placement will cause gpl to ocassionally run global routing (grt) during placement in order to determine routing congestion hotspots. gpl will then reweight the nets based on how congestion data. This process improves the routability of the netlist by spacing out cells in routing congested areas, but it also causes an increase in gpl runtime due to running global routing." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_ROUTABILITY_DRIVEN?","GPL_ROUTABILITY_DRIVEN toggles routability-driven global placement, influencing gpl runtime and netlist routability." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, CAP_MARGIN?",Specifies a capacitance margin when fixing max capacitance violations. This option allow you to overfix. +What does the CAP_MARGIN variable in Placement specify?,Specifies a capacitance margin when fixing max capacitance violations. This option allow you to overfix. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, CAP_MARGIN?",Sets a capacitance margin for overfixing max capacitance violations. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, SLEW_MARGIN?",Specifies a slew margin when fixing max slew violations. This option allow you to overfix. +How does the SLEW_MARGIN variable in Placement function?,Specifies a slew margin when fixing max slew violations. This option allow you to overfix. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, SLEW_MARGIN?",Sets a slew margin for overfixing max slew violations. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, CTS_ARGS?",Override clock_tree_synthesis arguments +What does the CTS_ARGS variable in Clock Tree Synthesis control?,Override clock_tree_synthesis arguments +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, CTS_ARGS?",Overrides arguments for clock tree synthesis. +What does CTS_BUF_CELL do in ORFS?,The CTS_BUF_CELL variable sets the root buffer cell used in the clock tree during clock tree synthesis (CTS) +What is the purpose of the CTS_BUF_CELL variable in ORFS?,The CTS_BUF_CELL variable sets the root buffer cell used in the clock tree during clock tree synthesis (CTS) +What does CTS_BUF_CELL do in ORFS?,CTS_BUF_CELL selects the root buffer cell for clock tree synthesis. +What is the use of the ORFS variable FILL_CELLS?,The FILL_CELLS variable holds a list of cell names to use as filler cells. Wildcard patterns (*) are supported. Fill cells are used to fill empty cell sites which aids in satisfying design rules and density rules. +How does the FILL_CELLS variable in ORFS function?,The FILL_CELLS variable holds a list of cell names to use as filler cells. Wildcard patterns (*) are supported. Fill cells are used to fill empty cell sites which aids in satisfying design rules and density rules. +What is the use of the ORFS variable FILL_CELLS?,"FILL_CELLS lists cell names for filler cells, supporting wildcards." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, HOLD_SLACK_MARGIN?",Specifies a time margin for the slack when fixing hold violations. This option allow you to overfix. +What does the HOLD_SLACK_MARGIN variable in Clock Tree Synthesis specify?,Specifies a time margin for the slack when fixing hold violations. This option allow you to overfix. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, HOLD_SLACK_MARGIN?",Specifies a time margin for fixing hold violations. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SETUP_SLACK_MARGIN?",Specifies a time margin for the slack when fixing setup violations. +How does the SETUP_SLACK_MARGIN variable in Clock Tree Synthesis operate?,Specifies a time margin for the slack when fixing setup violations. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SETUP_SLACK_MARGIN?",Specifies a time margin for setup violation fixes. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_GATE_CLONING?",Do not use gate cloning transform to fix timing violations (default: use gate cloning) +What does the SKIP_GATE_CLONING variable in Clock Tree Synthesis control?,Do not use gate cloning transform to fix timing violations (default: use gate cloning) +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_GATE_CLONING?",Disables gate cloning for timing violation fixes. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_PIN_SWAP?",Do not use pin swapping as a transform to fix timing violations (default: use pin swapping) +What does the SKIP_PIN_SWAP variable in Clock Tree Synthesis indicate?,Do not use pin swapping as a transform to fix timing violations (default: use pin swapping) +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_PIN_SWAP?",Disables pin swapping for timing violation fixes. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, TNS_END_PERCENT?","In OpenROAD Flow Scripts, the TNS_END_PERCENT variable specifies what percent of violating timing paths will be fixed during timing optimization. TNS_END_PERCENT must be a floating point value between 0-100. However, even if TNS_END_PERCENT is 0, the worst path will always be fixed. The purpose of this flag is to allow the user some control over how much runtime and logic area is spent on timing optimization, with a higher value leading to more runtime/area and a lower value leading to less runtime/area." +How does the TNS_END_PERCENT variable in Clock Tree Synthesis function?,"In OpenROAD Flow Scripts, the TNS_END_PERCENT variable specifies what percent of violating timing paths will be fixed during timing optimization. TNS_END_PERCENT must be a floating point value between 0-100. However, even if TNS_END_PERCENT is 0, the worst path will always be fixed. The purpose of this flag is to allow the user some control over how much runtime and logic area is spent on timing optimization, with a higher value leading to more runtime/area and a lower value leading to less runtime/area." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, TNS_END_PERCENT?",TNS_END_PERCENT defines the percent of timing path fixes during optimization. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, EQUIVALENCE_CHECK?","In OpenROAD Flow Scripts, the EQUIVALENCE_CHECK variable toggles whether a logical equivalence check is run after timing optimization to ensure logical correctness of the circuit. If EQUIVALENCE_CHECK is 1, the check is performed. If EQUIVALENCE_CHECK is any other value or unset, the check is not run. The default value is unset." +What does the EQUIVALENCE_CHECK variable in Clock Tree Synthesis specify?,"In OpenROAD Flow Scripts, the EQUIVALENCE_CHECK variable toggles whether a logical equivalence check is run after timing optimization to ensure logical correctness of the circuit. If EQUIVALENCE_CHECK is 1, the check is performed. If EQUIVALENCE_CHECK is any other value or unset, the check is not run. The default value is unset." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, EQUIVALENCE_CHECK?",EQUIVALENCE_CHECK toggles logical equivalence checks post-optimization. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, REMOVE_CELLS_FOR_EQY?","In OpenROAD Flow Scripts, the REMOVE_CELLS_FOR_EQY variable sets the list of cells to remove from the verilog netlist file produced specifically for netlist equivalence checking. Netlist equivalence checking is performed with the Yosys EQY tool. Wildcard patterns (*) are supported. This variable is passed directly to write_verilog -remove_cells <>." +How does the REMOVE_CELLS_FOR_EQY variable in Clock Tree Synthesis operate?,"In OpenROAD Flow Scripts, the REMOVE_CELLS_FOR_EQY variable sets the list of cells to remove from the verilog netlist file produced specifically for netlist equivalence checking. Netlist equivalence checking is performed with the Yosys EQY tool. Wildcard patterns (*) are supported. This variable is passed directly to write_verilog -remove_cells <>." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, REMOVE_CELLS_FOR_EQY?",REMOVE_CELLS_FOR_EQY lists cells to exclude from equivalence checking netlist files. +What is the difference between Yosys and OpenROAD?,Yosys is a logic synthesis tool which is responsible for transforming register transfer-level (RTL) code into a gate-level netlist. OpenROAD is a place and route (P&R) tool which is responsible for implementing a gale-level netlist into a chip layout. Yosys is developed by the YosysHQ organization whereas OpenROAD is developed by The OpenROAD Project. OpenROAD Flow Scripts (ORFS) makes use of both of these tools (as well as KLayout) to form a full RTL-to-GDS flow. +Can you contrast Yosys with OpenROAD in terms of functionality?,Yosys is a logic synthesis tool which is responsible for transforming register transfer-level (RTL) code into a gate-level netlist. OpenROAD is a place and route (P&R) tool which is responsible for implementing a gale-level netlist into a chip layout. Yosys is developed by the YosysHQ organization whereas OpenROAD is developed by The OpenROAD Project. OpenROAD Flow Scripts (ORFS) makes use of both of these tools (as well as KLayout) to form a full RTL-to-GDS flow. +What is the difference between Yosys and OpenROAD?,"Yosys transforms RTL code into a gate-level netlist, while OpenROAD handles P&R from netlist to chip layout." +Is there a simple way to open the GUI in ORFS?,"OpenROAD Flow Scripts (ORFS) includes Makefile targets to open the GUI after each step. You can use the command make gui_*, where * is the name of the flow step (e.g. make_floorplan)." +Is there a straightforward method to launch the GUI in ORFS?,"OpenROAD Flow Scripts (ORFS) includes Makefile targets to open the GUI after each step. You can use the command make gui_*, where * is the name of the flow step (e.g. make_floorplan)." +Is there a simple way to open the GUI in ORFS?,OpenROAD Flow Scripts include Makefile targets for GUI access after flow steps. \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.xlsx new file mode 100644 index 0000000..3cfbe75 Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Flow/Flow.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.csv new file mode 100644 index 0000000..34124e7 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.csv @@ -0,0 +1,216 @@ +Prompts,Answers +What is PDNGEN?,"The PDNGEN module (pdn) in OpenROAD aims to simplify the process of adding a power grid into a floorplan. A user can specify a small set of power grid policies to be applied to the design, such as the layers to use, stripe width, and spacing, and then pdn will generate the actual metal straps. Power grid policies can be defined over both the standard cell area and areas occupied by macros." +What is the essence of PDNGEN?,"The PDNGEN module (pdn) in OpenROAD aims to simplify the process of adding a power grid into a floorplan. A user can specify a small set of power grid policies to be applied to the design, such as the layers to use, stripe width, and spacing, and then pdn will generate the actual metal straps. Power grid policies can be defined over both the standard cell area and areas occupied by macros." +What is PDNGEN?,"OpenROAD's Power Distribution Network Generator (PDNGEN) module, abbreviated as pdn, streamlines the integration of a power grid into a design's floorplan. Users can establish a few power grid guidelines, such as selecting layers, setting stripe width, and spacing, after which pdn automatically constructs the metal straps. These guidelines can be applied across both the standard cell region and macro-occupied areas." +What is the structure of OpenDB?,The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library-style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures. +Can you describe the architecture of OpenDB?,The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library-style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures. +What is the structure of OpenDB?,"OpenDB's architecture mirrors the LEF (Library Exchange Format) and DEF (Design Exchange Format) text file standards version 5.6, supporting a binary file format for quicker design saving and loading than possible with LEF and DEF. Written in C++ 98, OpenDB employs standard library-style iterators and classes designed for rapid operation, obviating the need for copying into specific application structures." +How is FastRoute better than previous routing frameworks?,"FastRoute innovates over prior routing frameworks because it integrates several novel techniques: fast congestion-driven via-aware Steiner tree construction, 3-bend routing, virtual capacity adjustment, multi-source multi-sink maze routing, and spiral layer assignment. These techniques not only address the routing congestion measured at the edges of global routing grids but also minimize the total wirelength and via usage, which is critical for subsequent detailed routing, yield, and manufacturability. Experimental results show that FastRoute is highly effective and efficient in solving ISPD07 and ISPD08 global routing benchmark suites. The results outperform recently published academic global routers in both routability and runtime. In particular, for ISPD07 and ISPD08 global routing benchmarks, FastRoute generates 12 congestion-free solutions out of 16 benchmarks with a speed significantly faster than other routers." +In what ways is FastRoute superior to its predecessors in routing frameworks?,"FastRoute innovates over prior routing frameworks because it integrates several novel techniques: fast congestion-driven via-aware Steiner tree construction, 3-bend routing, virtual capacity adjustment, multi-source multi-sink maze routing, and spiral layer assignment. These techniques not only address the routing congestion measured at the edges of global routing grids but also minimize the total wirelength and via usage, which is critical for subsequent detailed routing, yield, and manufacturability. Experimental results show that FastRoute is highly effective and efficient in solving ISPD07 and ISPD08 global routing benchmark suites. The results outperform recently published academic global routers in both routability and runtime. In particular, for ISPD07 and ISPD08 global routing benchmarks, FastRoute generates 12 congestion-free solutions out of 16 benchmarks with a speed significantly faster than other routers." +How is FastRoute better than previous routing frameworks?,"FastRoute distinguishes itself from previous routing frameworks by integrating innovative approaches such as fast congestion-driven via-aware Steiner tree construction, 3-bend routing, virtual capacity adjustment, multi-source multi-sink maze routing, and spiral layer assignment. These methods tackle routing congestion at global routing grid edges and aim to minimize overall wirelength and via count, vital for detailed routing, yield, and manufacturability. According to tests, FastRoute excels in efficiency and effectiveness across ISPD07 and ISPD08 global routing benchmarks, outperforming contemporary academic routers in routability and speed, delivering congestion-free outcomes for 12 out of 16 benchmarks." +What does RTLMP do?,"A macro placer (MP) is an algorithm which specifically focuses on placing macros in the core area. RTL­MP is a novel macro placer that utilizes RTL information and tries to “mimic” the interaction between the frontend RTL designer and the back­ end physical design engineer to produce human­-quality floorplans. By exploiting the logical hierarchy and processing logical modules based on connection signatures, RTL­MP can capture the dataflow inherent in the RTL and use the dataflow information to guide macro placement." +What tasks does RTLMP accomplish?,"A macro placer (MP) is an algorithm which specifically focuses on placing macros in the core area. RTL­MP is a novel macro placer that utilizes RTL information and tries to “mimic” the interaction between the frontend RTL designer and the back­ end physical design engineer to produce human­-quality floorplans. By exploiting the logical hierarchy and processing logical modules based on connection signatures, RTL­MP can capture the dataflow inherent in the RTL and use the dataflow information to guide macro placement." +What does RTLMP do?,"A macro placer (MP) specifically targets macro placement within the core area. The novel RTL­MP leverages RTL data to emulate the collaborative process between frontend RTL designers and backend physical design engineers, producing floorplans of comparable quality to human-generated ones. By analyzing logical hierarchies and connections, RTL­MP captures the RTL's inherent data flow to inform its macro placement strategy." +What was the need to develop Hier-RTLMP?,"Recently, with the increasing complexity of IP blocks, and in particular with auto-generated RTL for machine learning (ML) accelerators, the number of macros in a single RTL block can easily run into several hundred. This makes the task of generating an automatic floorplan (.def) with IO pin and macro placements for front-end physical synthesis even more critical and challenging. The so-called peripheral approach of forcing macros to the periphery of the layout is no longer viable when the ratio of the sum of the macro perimeters to the floorplan perimeter is large since this increases the required stacking depth of macros. Thus, a novel multilevel physical planning approach that exploits the hierarchy and dataflow inherent in the design RTL, and describes its realization in a new hierarchical macro placer, Hier-RTLMP was developed. " +What prompted the creation of Hier-RTLMP?,"Recently, with the increasing complexity of IP blocks, and in particular with auto-generated RTL for machine learning (ML) accelerators, the number of macros in a single RTL block can easily run into several hundred. This makes the task of generating an automatic floorplan (.def) with IO pin and macro placements for front-end physical synthesis even more critical and challenging. The so-called peripheral approach of forcing macros to the periphery of the layout is no longer viable when the ratio of the sum of the macro perimeters to the floorplan perimeter is large since this increases the required stacking depth of macros. Thus, a novel multilevel physical planning approach that exploits the hierarchy and dataflow inherent in the design RTL, and describes its realization in a new hierarchical macro placer, Hier-RTLMP was developed. " +What was the need to develop Hier-RTLMP?,"The increasing complexity of IP blocks, especially auto-generated RTL for machine learning (ML) accelerators, has led to designs with hundreds of macros. This escalates the difficulty of automatically generating a floorplan (.def) that includes IO pin and macro placements for front-end physical synthesis. The traditional peripheral placement strategy becomes impractical when the macro perimeter sum greatly exceeds the floorplan's perimeter, necessitating a novel multilevel physical planning approach. This approach, realized in the Hier-RTLMP, leverages design RTL's inherent hierarchy and data flow for effective macro placement." +How is Hier-RTLMP different from RTL-MP?,"Hier-RTLMP consists of an auto-clustering engine that transforms the logical hierarchy into a physical hierarchy. Unlike RTL-MP where the physical hierarchy is a single level, Hier-RTLMP’s autoclustering engine creates a multilevel physical hierarchy of physical clusters. This enables the handling of large RTLs with hundreds of macros and allows for the placement of macros within the core area." +In what aspects does Hier-RTLMP diverge from RTL-MP?,"Hier-RTLMP consists of an auto-clustering engine that transforms the logical hierarchy into a physical hierarchy. Unlike RTL-MP where the physical hierarchy is a single level, Hier-RTLMP’s autoclustering engine creates a multilevel physical hierarchy of physical clusters. This enables the handling of large RTLs with hundreds of macros and allows for the placement of macros within the core area." +How is Hier-RTLMP different from RTL-MP?,"Hier-RTLMP introduces an auto-clustering engine that converts logical hierarchies into a multilevel physical structure. Unlike the single-level physical hierarchy in RTL-MP, Hier-RTLMP's engine facilitates managing extensive RTL designs with numerous macros, allowing for their strategic placement within the core area." +How does FastRoute work?,"The first part of the FastRoute framework is topology generation. Because FastRoute tries to avoid rip-up and reroute to reduce both wirelength and runtime, the initial tree topology has significant impacts. With the congestion-driven and via-aware topology, the next stage of FastRoute is actual routing. We find that there exists significant potential to improve traditional routing techniques in terms of via control and congestion reduction. The most commonly used routing techniques in global routing include L/Z/U pattern routing, monotonic routing, and maze routing. In addition to new topology and routing techniques, Fast Route integrates several performance enhancement techniques to further improve routing quality and reduce run time." +Can you explain the operating principle of FastRoute?,"The first part of the FastRoute framework is topology generation. Because FastRoute tries to avoid rip-up and reroute to reduce both wirelength and runtime, the initial tree topology has significant impacts. With the congestion-driven and via-aware topology, the next stage of FastRoute is actual routing. We find that there exists significant potential to improve traditional routing techniques in terms of via control and congestion reduction. The most commonly used routing techniques in global routing include L/Z/U pattern routing, monotonic routing, and maze routing. In addition to new topology and routing techniques, Fast Route integrates several performance enhancement techniques to further improve routing quality and reduce run time." +How does FastRoute work?,"FastRoute's framework begins with topology generation, aiming to minimize rip-up and reroute actions to reduce wirelength and runtime. The initial tree topology, based on congestion-driven and via-aware principles, sets the stage for the routing phase, which shows significant improvement opportunities over traditional methods in terms of via management and congestion alleviation. Besides innovative topology and routing strategies, FastRoute incorporates various performance-boosting techniques to enhance routing quality and efficiency." +Why is RSMT used more?,"Traditionally, global routing just uses tree structures like RMST or RSMT while RSMT is becoming more popular due to its minimal wirelength to connect a multi-pin net." +Why is RSMT favored over other methods?,"Traditionally, global routing just uses tree structures like RMST or RSMT while RSMT is becoming more popular due to its minimal wirelength to connect a multi-pin net." +Why is RSMT used more?,"Global routing traditionally utilizes tree structures such as RMST or RSMT, with RSMT growing in preference due to its efficiency in connecting multi-pin nets with minimal wirelength." +"Tab completion does work in console mode but not in GUI mode, why?","The OpenROAD GUI is made from custom Qt code and does not apply to the console. OpenROAD relies on the tclreadline package, which doesn't work well with imported namespaces." +Why does tab completion function in console mode but fail in GUI mode?,"The OpenROAD GUI is made from custom Qt code and does not apply to the console. OpenROAD relies on the tclreadline package, which doesn't work well with imported namespaces." +"Tab completion does work in console mode but not in GUI mode, why?","The OpenROAD GUI is built using custom Qt programming and is not applicable to command-line operations. It utilizes the tclreadline package, which faces compatibility issues with imported namespaces." +What is OpenDB?,"OpenDB is a design database to support tools for physical chip design. It was originally developed by Athena Design Systems. Nefelus, Inc. acquired the rights to the code and open-sourced it with BSD-3 license in 2019 to support the DARPA OpenROAD project. The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures." +What is the role of OpenDB?,"OpenDB is a design database to support tools for physical chip design. It was originally developed by Athena Design Systems. Nefelus, Inc. acquired the rights to the code and open-sourced it with BSD-3 license in 2019 to support the DARPA OpenROAD project. The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures." +What is OpenDB?,"OpenDB, originally developed by Athena Design Systems and later open-sourced by Nefelus, Inc. under a BSD-3 license for the DARPA OpenROAD project in 2019, serves as a database for physical chip design, utilizing LEF and DEF formats version 5.6 and supporting a binary format for efficient design loading and saving." +What is Automatic Code Generator used for?,The automatic code generator in OpenROAD is used to generate code for OpenDB objects and Iterators. It uses JSON input and automatically generates corresponding C++ files +What is the purpose behind the Automatic Code Generator?,The automatic code generator in OpenROAD is used to generate code for OpenDB objects and Iterators. It uses JSON input and automatically generates corresponding C++ files +What is Automatic Code Generator used for?,"OpenROAD's automatic code generator produces C++ files for OpenDB objects and iterators from JSON input, streamlining code generation." +What commands are used to read and write design data in OpenROAD?,"OpenROAD is run using Tcl scripts. The following commands are used to read and write design data. +read_lef [-tech] [-library] filename +read_def filename +write_def [-version 5.8|5.7|5.6|5.5|5.4|5.3] filename +read_verilog filename +write_verilog filename +read_db filename +write_db filename +write_abstract_lef filename" +"What support does OpenROAD have for Abstract LEF? +",OpenROAD contains an abstract LEF writer that can take your current design and emit an abstract LEF representing the external pins of your design and metal obstructions. Use the write_abstract_lef command to generate the abstract LEF. +How does OpenROAD support Abstract LEF?,OpenROAD contains an abstract LEF writer that can take your current design and emit an abstract LEF representing the external pins of your design and metal obstructions. Use the write_abstract_lef command to generate the abstract LEF. +"What support does OpenROAD have for Abstract LEF? +","The abstract LEF writer in OpenROAD allows for the creation of an abstract LEF from your design, detailing external pins and metal obstructions, using the write_abstract_lef command." +How does OpenROAD compute the die area when using the core_utilization argument in the initialize_floorplan?,"To compute the die area for the initialize_floorplan command, OpenROAD first calculates the core area by dividing the total logic area of the instances coming from synthesis and by the specified core_utilization. OpenROAD then shapes that core area based on the aspect_ratio parameter. Finally, OpenROAD expands the core area by adding a core margin on each edge of the core area. Altogether, this forms the die area." +How does OpenROAD determine die area with the core_utilization argument during floorplan initialization?,"To compute the die area for the initialize_floorplan command, OpenROAD first calculates the core area by dividing the total logic area of the instances coming from synthesis and by the specified core_utilization. OpenROAD then shapes that core area based on the aspect_ratio parameter. Finally, OpenROAD expands the core area by adding a core margin on each edge of the core area. Altogether, this forms the die area." +How does OpenROAD compute the die area when using the core_utilization argument in the initialize_floorplan?,"To calculate die area, OpenROAD first determines the core area by dividing the total logic area by the core utilization, shapes this area using the aspect ratio, and then expands it by adding core margins, resulting in the die area." +I would like to know if there is any way to write the log output from OpenROAD into a file (using a report_ type command)?,"To capture output from OpenROAD, you can use standard Unix file operations and redirections. OpenROAD outputs all messages directly to the stdout I/O stream." +Is there a method to direct OpenROAD's log output to a file?,"To capture output from OpenROAD, you can use standard Unix file operations and redirections. OpenROAD outputs all messages directly to the stdout I/O stream." +I would like to know if there is any way to write the log output from OpenROAD into a file (using a report_ type command)?,"Capturing OpenROAD output can be done using standard Unix redirections, as it sends all messages directly to the stdout stream." +What is the minimum number of metal layers OpenROAD can route in?,"OpenROAD has the theoretical ability to route as few as two layers, but it has rarely been tried by the developers due to the lack of a specialized channel router. It is expected that OpenROAD will hit some issues and have to iterate. If you try this and run into issues, please kindly file an issue on GitHub. However, if the PDK is proprietary, it will be more difficult for the OpenROAD team to diagnose and debug." +What is the minimum metal layer count that OpenROAD can handle for routing?,"OpenROAD has the theoretical ability to route as few as two layers, but it has rarely been tried by the developers due to the lack of a specialized channel router. It is expected that OpenROAD will hit some issues and have to iterate. If you try this and run into issues, please kindly file an issue on GitHub. However, if the PDK is proprietary, it will be more difficult for the OpenROAD team to diagnose and debug." +What is the minimum number of metal layers OpenROAD can route in?,"OpenROAD theoretically can route with as few as two layers, but this is rarely tested and may encounter issues, for which feedback on GitHub is appreciated, especially for proprietary PDKs." +"Can OpenROAD work with multi-VT cells (HVT, LVT, SVT) and swap between them in a single run?","OpenROAD supports using multi-VT cell libraries, and it can swap between VT cells during optimization." +Can OpenROAD manage cells with different threshold voltages within a single run?,"OpenROAD supports using multi-VT cell libraries, and it can swap between VT cells during optimization." +"Can OpenROAD work with multi-VT cells (HVT, LVT, SVT) and swap between them in a single run?","OpenROAD allows the use of multi-VT cell libraries, enabling swapping between VT cells during optimization phases." +Can OpenROAD work with Multi-Mode-Multi-Corner Files (mmmc) ?,"OpenROAD supports multi-corner Static Timing Analysis (STA), but it doesn't currently support multi-mode STA. ""MMMC"" files from proprietary tools are stored in proprietary formats, which OpenROAD cannot support. The OpenSTA manual will contain more information about how to run multi-corner analysis." +Is OpenROAD compatible with Multi-Mode-Multi-Corner Files?,"OpenROAD supports multi-corner Static Timing Analysis (STA), but it doesn't currently support multi-mode STA. ""MMMC"" files from proprietary tools are stored in proprietary formats, which OpenROAD cannot support. The OpenSTA manual will contain more information about how to run multi-corner analysis." +Can OpenROAD work with Multi-Mode-Multi-Corner Files (mmmc) ?,"While OpenROAD supports multi-corner Static Timing Analysis, it does not yet accommodate multi-mode STA due to proprietary format constraints of ""MMMC"" files." +What does Antenna Rule Checker do?,"This tool checks antenna violations and generates a report to indicate violated nets. See LEF/DEF 5.8 Language Reference, Appendix C, ""Calculating and Fixing Process Antenna Violations"" (p.389) for a description of antenna violations." +How does the Antenna Rule Checker contribute to design integrity?,"This tool checks antenna violations and generates a report to indicate violated nets. See LEF/DEF 5.8 Language Reference, Appendix C, ""Calculating and Fixing Process Antenna Violations"" (p.389) for a description of antenna violations." +What does Antenna Rule Checker do?,"The tool checks for antenna violations and reports nets that violate these rules, with guidance found in the LEF/DEF 5.8 Language Reference." +What is Clock Tree Synthesis in OpenROAD?,"Clock tree synthesis (CTS) is the step of distributing a clock to all endpoints (such as flip-flops) while trying to minimize power and skew (the different in clock arrival times between two registers). The clock tree synthesis module in OpenROAD (cts) is based on TritonCTS 2.0, and can be run using the clock_tree_synthesis command. TritonCTS 2.0 features on-the-fly characterization, and therefore does not need to pre-generate characterization data. The on-the-fly characterization feature can be optionally controlled by parameters specified by the configure_cts_characterization command. You can use the set_wire_rc command to set the clock routing layer used when calculating parasitics in this step." +What entails Clock Tree Synthesis in OpenROAD?,"Clock tree synthesis (CTS) is the step of distributing a clock to all endpoints (such as flip-flops) while trying to minimize power and skew (the different in clock arrival times between two registers). The clock tree synthesis module in OpenROAD (cts) is based on TritonCTS 2.0, and can be run using the clock_tree_synthesis command. TritonCTS 2.0 features on-the-fly characterization, and therefore does not need to pre-generate characterization data. The on-the-fly characterization feature can be optionally controlled by parameters specified by the configure_cts_characterization command. You can use the set_wire_rc command to set the clock routing layer used when calculating parasitics in this step." +What is Clock Tree Synthesis in OpenROAD?,"Clock tree synthesis in OpenROAD, facilitated by TritonCTS 2.0, distributes clock signals to endpoints while minimizing power and skew, offering on-the-fly characterization to avoid pre-generated data needs." +Tell me about Detailed Placement in OpenROAD?,"The detailed placement module in OpenROAD (dpl) is based on OpenDP or Open-Source Detailed Placement Engine. Its key features are +fence region and fragmented ROWs." +What does Detailed Placement involve in OpenROAD?,"The detailed placement module in OpenROAD (dpl) is based on OpenDP or Open-Source Detailed Placement Engine. Its key features are +fence region and fragmented ROWs." +Tell me about Detailed Placement in OpenROAD?,"The detailed placement module, based on OpenDP, focuses on fence regions and fragmented rows for placement optimization." +Describe the Restructure module in OpenROAD?,The restructure module in OpenROAD (rmp) is based on an interface to ABC for local resynthesis. The package allows logic restructuring that targets area or timing. It extracts a cloud of logic using the OpenSTA timing engine and passes it to ABC through the blif interface. Multiple recipes for area or timing are run to obtain multiple structures from ABC; the most desirable among these is used to improve the netlist. The ABC output is read back by a blif reader which is integrated into OpenDB. Blif writer and reader also support constants from and to OpenDB. Reading back of constants requires insertion of tie cells which should be provided by the user as per the interface described below. +Can you outline the Restructure module's role in OpenROAD?,The restructure module in OpenROAD (rmp) is based on an interface to ABC for local resynthesis. The package allows logic restructuring that targets area or timing. It extracts a cloud of logic using the OpenSTA timing engine and passes it to ABC through the blif interface. Multiple recipes for area or timing are run to obtain multiple structures from ABC; the most desirable among these is used to improve the netlist. The ABC output is read back by a blif reader which is integrated into OpenDB. Blif writer and reader also support constants from and to OpenDB. Reading back of constants requires insertion of tie cells which should be provided by the user as per the interface described below. +Describe the Restructure module in OpenROAD?,"The restructure module interfaces with ABC for logic resynthesis aimed at area or timing improvement, utilizing OpenSTA for logic extraction and integrating ABC's output through OpenDB's blif reader and writer." +Describe Parallax Static Timing Analyzer or OpenSTA?,"OpenSTA is a gate-level static timing verifier. As a stand-alone executable, it can be used to verify the timing of a design using standard file formats. OpenSTA uses a TCL command interpreter to read the design, specify timing constraints, and print timing reports." +What capabilities does the Parallax Static Timing Analyzer offer?,"OpenSTA is a gate-level static timing verifier. As a stand-alone executable, it can be used to verify the timing of a design using standard file formats. OpenSTA uses a TCL command interpreter to read the design, specify timing constraints, and print timing reports." +Describe Parallax Static Timing Analyzer or OpenSTA?,"OpenSTA performs gate-level static timing analysis, using TCL for design reading, timing constraints specification, and timing report generation." +What is DFT?,This tool is an implementation of Design For Testing. New nets and logic are added to allow IC designs to be tested for errors in manufacturing. Physical imperfections can cause hard failures and variability can cause timing errors. +Can you elaborate on DFT?,This tool is an implementation of Design For Testing. New nets and logic are added to allow IC designs to be tested for errors in manufacturing. Physical imperfections can cause hard failures and variability can cause timing errors. +What is DFT?,"This tool implements Design For Testing (DFT) by introducing new nets and logic, facilitating the testing of IC designs for manufacturing errors. It addresses physical defects and variability, which can lead to hard failures and timing errors, respectively." +What is Read UPF Utility?,"This module contains functionality to read, and modify information from Unified Power Format (UPF) files." +What functionality does the Read UPF Utility offer?,"This module contains functionality to read, and modify information from Unified Power Format (UPF) files." +What is Read UPF Utility?,This module offers tools to access and alter information within Unified Power Format (UPF) files. +Explain Chip-level Connections in OpenROAD?,"The chip-level connections module in OpenROAD (pad) is based on the open-source tool ICeWall. In this utility, either place an IO ring around the boundary of the chip and connect with either wirebond pads or a bump array." +How are chip-level connections managed in OpenROAD?,"The chip-level connections module in OpenROAD (pad) is based on the open-source tool ICeWall. In this utility, either place an IO ring around the boundary of the chip and connect with either wirebond pads or a bump array." +Explain Chip-level Connections in OpenROAD?,"OpenROAD's chip-level connections module (pad) utilizes the open-source ICeWall tool to place an IO ring around the chip's boundary, connecting through wirebond pads or a bump array." +Brief me on the parasitics extraction module?,"The parasitics extraction module in OpenROAD (rcx) is based on the open-source OpenRCX, a Parasitic Extraction (PEX, or RCX) tool that works on OpenDB design APIs. It extracts routed designs based on the LEF/DEF layout model. +OpenRCX extracts both Resistance and Capacitance for wires, based on coupling distance to the nearest wire and the track density context over and/or under the wire of interest, as well as cell abstracts. The capacitance and resistance measurements are based on equations of coupling distance interpolated on exact measurements from a calibration file, called the Extraction Rules file. The Extraction Rules file (RC technology file) is generated once for every process node and corner, using a provided utility for DEF wire pattern generation and regression modeling. +OpenRCX stores resistance, coupling capacitance, and ground (i.e., grounded) capacitance on OpenDB objects with direct pointers to the associated wire and via db objects. Optionally, OpenRCX can generate a .spef file." +Can you brief me on the parasitics extraction module?,"The parasitics extraction module in OpenROAD (rcx) is based on the open-source OpenRCX, a Parasitic Extraction (PEX, or RCX) tool that works on OpenDB design APIs. It extracts routed designs based on the LEF/DEF layout model. +OpenRCX extracts both Resistance and Capacitance for wires, based on coupling distance to the nearest wire and the track density context over and/or under the wire of interest, as well as cell abstracts. The capacitance and resistance measurements are based on equations of coupling distance interpolated on exact measurements from a calibration file, called the Extraction Rules file. The Extraction Rules file (RC technology file) is generated once for every process node and corner, using a provided utility for DEF wire pattern generation and regression modeling. +OpenRCX stores resistance, coupling capacitance, and ground (i.e., grounded) capacitance on OpenDB objects with direct pointers to the associated wire and via db objects. Optionally, OpenRCX can generate a .spef file." +Brief me on the parasitics extraction module?,"The parasitics extraction module in OpenROAD, based on OpenRCX, performs parasitic extraction on routed designs using the LEF/DEF model. It calculates wire resistance and capacitance by considering coupling distance and track density, utilizing a calibration file for accurate measurements. OpenRCX can also produce a .spef file for further analysis." +What is global routing?,"The global routing module in OpenROAD (grt) is based on FastRoute, an open-source global router originally derived from Iowa State University's FastRoute4.1 algorithm. Global routing is responsible for creating routing guides for each net to simplify the job of the detailed router. The purpose of global routing is mainly to avoid overcongestion when creating the guides." +Can you explain global routing and its importance?,"The global routing module in OpenROAD (grt) is based on FastRoute, an open-source global router originally derived from Iowa State University's FastRoute4.1 algorithm. Global routing is responsible for creating routing guides for each net to simplify the job of the detailed router. The purpose of global routing is mainly to avoid overcongestion when creating the guides." +What is global routing?,"OpenROAD's global routing module, built on the FastRoute algorithm, creates routing guides for each net to manage congestion during detailed routing, aiming to prevent overcongestion." +Which environment is required for setting up OpenROAD flow scripts?,You can use the bash shell to run commands and scripts. +What setup is necessary for OpenROAD flow scripts?,You can use the bash shell to run commands and scripts. +Which environment is required for setting up OpenROAD flow scripts?,The bash shell facilitates command and script execution. +What are the ways of installing OpenROAD flow scripts/ ORFS?,"These are the ways of installing OpenROAD flow scripts/ ORFS: Docker, Pre-built Binaries, Windows Subsystem for Linux (WSL), and Local Installation." +What installation methods exist for OpenROAD flow scripts/ORFS?,"These are the ways of installing OpenROAD flow scripts/ ORFS: Docker, Pre-built Binaries, Windows Subsystem for Linux (WSL), and Local Installation." +What are the ways of installing OpenROAD flow scripts/ ORFS?,"OpenROAD flow scripts can be installed via Docker, Pre-built Binaries, WSL, or Local Installation." +What is the basic build command for OpenROAD flow scripts/ ORFS?,The basic basic build command in ORFS is ./build_openroad.sh --help. +What is the fundamental build command for OpenROAD flow scripts/ORFS?,The basic basic build command in ORFS is ./build_openroad.sh --help. +What is the basic build command for OpenROAD flow scripts/ ORFS?,The fundamental ORFS build command is ./build_openroad.sh --help. +What is OpenROAD?,"The OpenROAD (""Foundations and Realization of Open, Accessible Design"") Project was launched in June 2018 within the DARPA IDEA program. OpenROAD aims to bring down the barriers of cost, expertise, and unpredictability that currently block designers' access to hardware implementation in advanced technologies. The project team is developing a fully autonomous, open-source toolchain for digital SoC layout generation, focusing on the RTL-to-GDSII phase of system-on-chip design. Thus, OpenROAD holistically attacks the multiple facets of today's design cost crisis: engineering resources, design tool licenses, project schedule, and risk." +Can you provide an overview of OpenROAD and its functionalities?,"The OpenROAD (""Foundations and Realization of Open, Accessible Design"") Project was launched in June 2018 within the DARPA IDEA program. OpenROAD aims to bring down the barriers of cost, expertise, and unpredictability that currently block designers' access to hardware implementation in advanced technologies. The project team is developing a fully autonomous, open-source toolchain for digital SoC layout generation, focusing on the RTL-to-GDSII phase of system-on-chip design. Thus, OpenROAD holistically attacks the multiple facets of today's design cost crisis: engineering resources, design tool licenses, project schedule, and risk." +What is OpenROAD?,"Launched in June 2018 under DARPA's IDEA program, the OpenROAD (""Foundations and Realization of Open, Accessible Design"") Project aims to democratize access to hardware implementation in cutting-edge technologies by developing a fully autonomous, open-source toolchain for digital SoC layout from RTL-to-GDSII. This initiative addresses the design cost crisis from various angles, including engineering resources, tool licenses, project timelines, and risk." +What is AutoTuner?,"AutoTuner is a ""no-human-in-loop"" parameter tuning framework for commercial and academic RTL-to-GDS flows. AutoTuner provides a generic interface where users can define parameter configuration as JSON objects. This enables AutoTuner to easily support various tools and flows. AutoTuner also utilizes METRICS2.1 to capture PPA of individual search trials. With the abundant features of METRICS2.1, users can explore various reward functions that steer the flow autotuning to different PPA goals." +What is AutoTuner and its purpose in OpenROAD?,"AutoTuner is a ""no-human-in-loop"" parameter tuning framework for commercial and academic RTL-to-GDS flows. AutoTuner provides a generic interface where users can define parameter configuration as JSON objects. This enables AutoTuner to easily support various tools and flows. AutoTuner also utilizes METRICS2.1 to capture PPA of individual search trials. With the abundant features of METRICS2.1, users can explore various reward functions that steer the flow autotuning to different PPA goals." +What is AutoTuner?,"AutoTuner, a ""no-human-in-loop"" framework, facilitates parameter tuning across commercial and academic RTL-to-GDS flows. It employs a generic interface for parameter configurations via JSON objects and leverages METRICS2.1 to evaluate PPA across trials, supporting the exploration of diverse PPA-optimizing reward functions." +WHat are the current supported search algorithms by AutoTuner?,"AutoTuner contains top-level Python script for ORFS, each of which implements a different search algorithm. Current supported search algorithms are as follows: +Random/Grid Search, Population Based Training (PBT), Tree Parzen Estimator (HyperOpt), Bayesian + Multi-Armed Bandit (AxSearch), Tree Parzen Estimator + Covariance Matrix Adaptation Evolution Strategy (Optuna), Evolutionary Algorithm (Nevergrad)" +Which search algorithms are currently supported by AutoTuner?,"AutoTuner contains top-level Python script for ORFS, each of which implements a different search algorithm. Current supported search algorithms are as follows: +Random/Grid Search, Population Based Training (PBT), Tree Parzen Estimator (HyperOpt), Bayesian + Multi-Armed Bandit (AxSearch), Tree Parzen Estimator + Covariance Matrix Adaptation Evolution Strategy (Optuna), Evolutionary Algorithm (Nevergrad)" +WHat are the current supported search algorithms by AutoTuner?,"AutoTuner incorporates a top-level Python script for ORFS, offering various search algorithms like Random/Grid Search, Population Based Training (PBT), Tree Parzen Estimator (HyperOpt), Bayesian + Multi-Armed Bandit (AxSearch), Tree Parzen Estimator + Covariance Matrix Adaptation Evolution Strategy (Optuna), and Evolutionary Algorithm (Nevergrad)." +How to set the direction of tuning in AutoTuner?,"User-defined coefficient values (coeff_perform, coeff_power, coeff_area) of three objectives to set the direction of tuning are written in the script. Each coefficient is expressed as a global variable at the get_ppa function in PPAImprov class in the script (coeff_perform, coeff_power, coeff_area). Efforts to optimize each of the objectives are proportional to the specified coefficients." +How can the tuning direction be set in AutoTuner?,"User-defined coefficient values (coeff_perform, coeff_power, coeff_area) of three objectives to set the direction of tuning are written in the script. Each coefficient is expressed as a global variable at the get_ppa function in PPAImprov class in the script (coeff_perform, coeff_power, coeff_area). Efforts to optimize each of the objectives are proportional to the specified coefficients." +How to set the direction of tuning in AutoTuner?,"In AutoTuner, user-defined coefficient values (coeff_perform, coeff_power, coeff_area) direct the tuning efforts towards optimizing performance, power, and area. These coefficients are globally declared in the PPAImprov class's get_ppa function." +What environment is required for AutoTuner?,"To set up AutoTuner, make sure you have a virtual environment set up with Python 3.9.X. There are plenty of ways to do this, we recommend using Miniconda, which is a free minimal installer for the package manager conda." +What environment is necessary for operating AutoTuner?,"To set up AutoTuner, make sure you have a virtual environment set up with Python 3.9.X. There are plenty of ways to do this, we recommend using Miniconda, which is a free minimal installer for the package manager conda." +What environment is required for AutoTuner?,"To initiate AutoTuner, ensure the setup of a virtual environment using Python 3.9.X, with Miniconda recommended for managing the environment." +Which parameters/variables can be used for tune or sweep?,Any variable that can be set from the command line can be used for tune or sweep. +What parameters or variables can be tuned or swept in AutoTuner?,Any variable that can be set from the command line can be used for tune or sweep. +Which parameters/variables can be used for tune or sweep?,Variables settable via command line can be employed for tuning or sweeping parameters. +How to add verilog designs to ORFS repository for a full RTL-GDS flow execution?,The following design example is based on the design spm that implements a Single-port memory using gf180 platform. This procedure applies to any design for a given platform you choose. Start from the base directory OpenROAD-flow-scripts/flow. Step 1: Create the Verilog source files directory based on the top module name. Step 2: Create config.mk to define design configuration. Step 3: Define key design parameters in config.mk. Step 4: Define SDC constraints. Step 5: Add the design name to Makefile to run the flow with the make command. +How can Verilog designs be added to the ORFS repository for complete RTL-GDSII flow execution?,The following design example is based on the design spm that implements a Single-port memory using gf180 platform. This procedure applies to any design for a given platform you choose. Start from the base directory OpenROAD-flow-scripts/flow. Step 1: Create the Verilog source files directory based on the top module name. Step 2: Create config.mk to define design configuration. Step 3: Define key design parameters in config.mk. Step 4: Define SDC constraints. Step 5: Add the design name to Makefile to run the flow with the make command. +How to add verilog designs to ORFS repository for a full RTL-GDS flow execution?,"Describing a design example for a Single-port memory using the gf180 platform, this process is adaptable to any design. It includes creating a Verilog source directory, configuring design settings in config.mk, defining key parameters, setting SDC constraints, and incorporating the design into the Makefile for execution." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLATFORM?","While designing spm that implements a Single-port memory using gf180 platform, the export PLATFORM value can be gf180." +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export PLATFORM?","While designing spm that implements a Single-port memory using gf180 platform, the export PLATFORM value can be gf180." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLATFORM?","For a Single-port memory design on the gf180 platform, the export PLATFORM variable should be set to gf180." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export DESIGN_NAME?","While designing spm that implements a Single-port memory using gf180 platform, the value of the parameter, export DESIGN_NAME can be spm." +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export DESIGN_NAME?","While designing spm that implements a Single-port memory using gf180 platform, the value of the parameter, export DESIGN_NAME can be spm." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export DESIGN_NAME?","When designing a Single-port memory on the gf180 platform, the export DESIGN_NAME should be assigned to spm." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export VERILOG_FILES?","For the value of export VERILOG_FILES parameter while designing spm that implements a Single-port memory using gf180 platform, it can be $(sort $(wildcard ./designs/src/$(DESIGN_NICKNAME)/*.v))" +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export VERILOG_FILES?","For the value of export VERILOG_FILES parameter while designing spm that implements a Single-port memory using gf180 platform, it can be $(sort $(wildcard ./designs/src/$(DESIGN_NICKNAME)/*.v))" +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export VERILOG_FILES?",The export VERILOG_FILES parameter should be set to include all Verilog files under the design nickname directory for a Single-port memory design on the gf180 platform. +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export SDC_FILE?","The parameter, export SDC_FILE can have the value ./designs/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc while designing spm that implements a Single-port memory using gf180 platform" +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export SDC_FILE?","The parameter, export SDC_FILE can have the value ./designs/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc while designing spm that implements a Single-port memory using gf180 platform" +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export SDC_FILE?","While designing a Single-port memory on the gf180 platform, the export SDC_FILE parameter should be set to the constraint file path." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export CORE_UTILIZATION?", The value of CORE_UTILIZATION may be subjective but one value for CORE_UTILIZATION while designing spm that implements a Single-port memory using gf180 platform40 +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export CORE_UTILIZATION?", The value of CORE_UTILIZATION may be subjective but one value for CORE_UTILIZATION while designing spm that implements a Single-port memory using gf180 platform40 +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export CORE_UTILIZATION?","The CORE_UTILIZATION value, while subjective, could be set to 40 for a Single-port memory design on the gf180 platform." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLACE_DENSITY ","The value of the parameter, export PLACE_DENSITY while designing spm that implements a Single-port memory can be 0.6." +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export PLACE_DENSITY?","The value of the parameter, export PLACE_DENSITY while designing spm that implements a Single-port memory can be 0.6." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLACE_DENSITY ","For a Single-port memory design, the export PLACE_DENSITY should be set to 0.6." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export TNS_END_PERCENT?","The value of the parameter, export TNS_END_PERCENT while designing spm that implements a Single-port memory can be 100." +"For a Single-port memory design using the gf180 platform, what should be the value for the parameter, export TNS_END_PERCENT?","The value of the parameter, export TNS_END_PERCENT while designing spm that implements a Single-port memory can be 100." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export TNS_END_PERCENT?","In the case of a Single-port memory design, the export TNS_END_PERCENT should be 100." +What is the function of the Environment Variables for the OpenROAD Flow Scripts?,"Environment variables are used in the OpenROAD flow to define various platform, design, and tool-specific variables to allow finer control and user overrides at various flow stages. These are defined in the config.mk file located in the platform and design-specific directories." +How do Environment Variables influence the OpenROAD Flow Scripts?,"Environment variables are used in the OpenROAD flow to define various platform, design, and tool-specific variables to allow finer control and user overrides at various flow stages. These are defined in the config.mk file located in the platform and design-specific directories." +What is the function of the Environment Variables for the OpenROAD Flow Scripts?,"The OpenROAD flow utilizes environment variables defined in the config.mk file to specify various platform, design, and tool-specific settings, offering detailed control and customization at different stages." +"What does the general variables for all stages, SKIP_REPORT_METRICS do?","The SKIP_REPORT_METRICS general variable if set to 1, then metrics, report_metrics does nothing. This is useful to speed up builds." +What is the role of the SKIP_REPORT_METRICS variable in all stages?,"The SKIP_REPORT_METRICS general variable if set to 1, then metrics, report_metrics does nothing. This is useful to speed up builds." +"What does the general variables for all stages, SKIP_REPORT_METRICS do?","If the SKIP_REPORT_METRICS variable is set to 1, metrics and report_metrics are bypassed, which accelerates the build process." +"Can you explain the usage of the Library Setup variable, PROCESS?","The variable, PROCESS signifies a technology node or process in use." +Can you detail the PROCESS variable in Library Setup?,"The variable, PROCESS signifies a technology node or process in use." +"Can you explain the usage of the Library Setup variable, PROCESS?",The PROCESS variable indicates the technology node or process in use. +"What is the function of the Library Setup variable, CORNER?",This CORNER variable specifies the Library to select based on corner BC/TC/WC. +What is the purpose of the CORNER variable in Library Setup?,This CORNER variable specifies the Library to select based on corner BC/TC/WC. +"What is the function of the Library Setup variable, CORNER?",The CORNER variable determines the Library selection based on corner cases like BC/TC/WC. +"What is the description of Library Setup variable, TECH_LEF","This variable, TECH_LEF, stipulates a technology LEF file of the PDK that includes all relevant information regarding metal layers, vias, and spacing requirements." +What does the TECH_LEF variable in Library Setup describe?,"This variable, TECH_LEF, stipulates a technology LEF file of the PDK that includes all relevant information regarding metal layers, vias, and spacing requirements." +"What is the description of Library Setup variable, TECH_LEF","TECH_LEF defines a technology LEF file from the PDK containing details on metal layers, vias, and spacing requirements." +"What is the description of Library Setup variable, SC_LEF",SC_LEF is used to specify the path to the technology standard cell LEF file. +What does the SC_LEF variable in Library Setup denote?,SC_LEF is used to specify the path to the technology standard cell LEF file. +"What is the description of Library Setup variable, SC_LEF",SC_LEF specifies the path to the technology standard cell LEF file. +"What is the function of the Library Setup variable, GDS_FILES",GDS_FILES specifies the path to platform GDS files. +What is the role of the GDS_FILES variable in Library Setup?,GDS_FILES specifies the path to platform GDS files. +"What is the function of the Library Setup variable, GDS_FILES",GDS_FILES sets the path to platform GDS files. +"What is the description of Library Setup variable, LIB_FILES","LIB_FILES enumerates a Liberty file of the standard cell library with PVT characterization, input and output characteristics, timing, and power definitions for each cell." +What does the LIB_FILES variable in Library Setup specify?,"LIB_FILES enumerates a Liberty file of the standard cell library with PVT characterization, input and output characteristics, timing, and power definitions for each cell." +"What is the description of Library Setup variable, LIB_FILES","LIB_FILES lists a Liberty file for the standard cell library, including PVT characterization, and definitions of input/output characteristics, timing, and power for each cell." +"Can you explain the usage of the Library Setup variable, DONT_USE_CELLS?","In OpenROAD Flow Scripts, the DONT_USE_CELLS variable stores a list of cells to avoid when performing both synthesis and place & route. Basic wildcard patterns (*) are supported. You may want to mark a cell as dont_use for several reasons, including 1) some cells may have complicated pin access patterns which are more likely to cause design rule violations during detailed routing, 2) some cells may be more prone to manufacturing variation, and will cause difficulty to close timing constraints, 3) A designer may not want to use certain cells during the implementation flow." +How is the DONT_USE_CELLS variable used in Library Setup?,"In OpenROAD Flow Scripts, the DONT_USE_CELLS variable stores a list of cells to avoid when performing both synthesis and place & route. Basic wildcard patterns (*) are supported. You may want to mark a cell as dont_use for several reasons, including 1) some cells may have complicated pin access patterns which are more likely to cause design rule violations during detailed routing, 2) some cells may be more prone to manufacturing variation, and will cause difficulty to close timing constraints, 3) A designer may not want to use certain cells during the implementation flow." +"Can you explain the usage of the Library Setup variable, DONT_USE_CELLS?","In OpenROAD Flow Scripts, DONT_USE_CELLS stores cells to avoid during synthesis and place & route, supporting basic wildcard patterns (*), due to reasons like complex pin access, susceptibility to manufacturing variation, or simply preference." +What does restructuring do?,"Restructuring (the rst module) uses logic resynthesis to optimize combinational logic paths. Restructuring can be performed in either area or delay mode. Area mode will optimize the logic cell area of the paths, whereas delay mode will optimize for delay. An Area Mode Example: restructure -liberty_file ckt.lib -target area -tielo_pin ABC -tiehi_pin DEF. For Timing Mode Example: restructure -liberty_file ckt.lib -target delay -tielo_pin ABC -tiehi_pin DEF -slack_threshold 1 -depth_threshold 2." +How does restructuring contribute to design optimization?,"Restructuring (the rst module) uses logic resynthesis to optimize combinational logic paths. Restructuring can be performed in either area or delay mode. Area mode will optimize the logic cell area of the paths, whereas delay mode will optimize for delay. An Area Mode Example: restructure -liberty_file ckt.lib -target area -tielo_pin ABC -tiehi_pin DEF. For Timing Mode Example: restructure -liberty_file ckt.lib -target delay -tielo_pin ABC -tiehi_pin DEF -slack_threshold 1 -depth_threshold 2." +What does restructuring do?,Restructuring optimizes combinational logic paths in area or delay modes. +Is there a way of knowing which instances were modified by resize command ?,"The Resizer module (rsz) can modify the netlist by inserting or removing buffers, as well as increasing or decreasing the drive strength of cells. rsz does not save a log of which instances were modified, because it would create an excessively long log file. A recommended workaround solution would be to save a layout file (such as DEF or ODB) before performing resizing, and then compare it to a layout file after resizing." +Is it possible to identify instances modified by the resize command?,"The Resizer module (rsz) can modify the netlist by inserting or removing buffers, as well as increasing or decreasing the drive strength of cells. rsz does not save a log of which instances were modified, because it would create an excessively long log file. A recommended workaround solution would be to save a layout file (such as DEF or ODB) before performing resizing, and then compare it to a layout file after resizing." +Is there a way of knowing which instances were modified by resize command ?,Resizer modifies the netlist by adjusting buffer sizes and cell drive strengths without detailed modification logs. +How can I improve runtime?,"In OpenROAD, the runtime of the software is directly related to 1) the modeling accuracy and 2) the circuit optimization effort. Improving runtime is usually a tradeoff of one of these two categories. If you are comfortable with reducing optimization effort, such as when performing design space exploration, you could try the following techniques: 1) Relaxing timing constraints in the SDC file, 2) skipping unnesessary optimization routines, such as setup and hold time fixing, 3) Stopping the design flow early, such as after the placement step or clock tree synthesis (CTS) step." +How might I enhance the runtime efficiency of my design?,"In OpenROAD, the runtime of the software is directly related to 1) the modeling accuracy and 2) the circuit optimization effort. Improving runtime is usually a tradeoff of one of these two categories. If you are comfortable with reducing optimization effort, such as when performing design space exploration, you could try the following techniques: 1) Relaxing timing constraints in the SDC file, 2) skipping unnesessary optimization routines, such as setup and hold time fixing, 3) Stopping the design flow early, such as after the placement step or clock tree synthesis (CTS) step." +How can I improve runtime?,"OpenROAD runtime is influenced by modeling accuracy and optimization efforts, with trade-offs for runtime improvement." +Why does my design take so long?,"In OpenROAD, the runtime of the design can be affected by several factors: 1) the size of the netlist. Designs with a large number of instances (100k or more) can take significantly longer than small designs. 2) the physical area of the design. Designs with large die areas (~1 mm^2 or larger) can take longer because of having to store the die size in memory. 3) improper timing constraints. Designs with excessive timing constaints can cause optimization algorithms, particularly Resizer (rsz) to take excessively long. 4) host machine constraints. Large designs can require a large amount of RAM to run. If the required memory exceeds your machine's available memory, the runtime will be significantly increased. Additionally, OpenROAD scales well with core count, so using a CPU with a greater number of cores can improve runtime." +What factors contribute to prolonged design processing times?,"In OpenROAD, the runtime of the design can be affected by several factors: 1) the size of the netlist. Designs with a large number of instances (100k or more) can take significantly longer than small designs. 2) the physical area of the design. Designs with large die areas (~1 mm^2 or larger) can take longer because of having to store the die size in memory. 3) improper timing constraints. Designs with excessive timing constaints can cause optimization algorithms, particularly Resizer (rsz) to take excessively long. 4) host machine constraints. Large designs can require a large amount of RAM to run. If the required memory exceeds your machine's available memory, the runtime will be significantly increased. Additionally, OpenROAD scales well with core count, so using a CPU with a greater number of cores can improve runtime." +Why does my design take so long?,"Netlist size, design area, timing constraints, and machine capabilities affect OpenROAD's runtime." +What is DBU?,"In OpenROAD, database units (DBU) are an integer representation of distance on a chip. In the LEF/DEF format, each technology specifies a conversion factor in terms of DBU/micron. For example, if a technology used a conversion factor of 2000 DBU/micron, that would mean that each DBU represents 0.0005 micron or 0.5 nm. The purpose for using DBU is that it enables faster calculation and no loss of precision compared to floating point representations." +Can you explain the concept of DBU in OpenROAD?,"In OpenROAD, database units (DBU) are an integer representation of distance on a chip. In the LEF/DEF format, each technology specifies a conversion factor in terms of DBU/micron. For example, if a technology used a conversion factor of 2000 DBU/micron, that would mean that each DBU represents 0.0005 micron or 0.5 nm. The purpose for using DBU is that it enables faster calculation and no loss of precision compared to floating point representations." +What is DBU?,"Database units (DBU) represent distance on a chip, converting to microns for precision without floating point errors." +How do I convert from DBU?,"In OpenROAD, an integer DBU value can be converted to a floating point micron value by using the ord::dbu_to_microns function" +How is conversion from DBU performed?,"In OpenROAD, an integer DBU value can be converted to a floating point micron value by using the ord::dbu_to_microns function" +How do I convert from DBU?,DBU values convert to microns using ord::dbu_to_microns function. +How to access GUI,OpenROAD's GUI can be started in two ways. One is to use the -gui flag when invoking OpenROAD from the command line (e.g. openroad -gui). The other option is to use the gui::show function from inside the openroad command interpreter. +How can the GUI be accessed in OpenROAD?,OpenROAD's GUI can be started in two ways. One is to use the -gui flag when invoking OpenROAD from the command line (e.g. openroad -gui). The other option is to use the gui::show function from inside the openroad command interpreter. +How to access GUI,OpenROAD's GUI is accessible via command line flag or internal show function. +Which commands are essential for manipulating design data in OpenROAD?,"OpenROAD is run using Tcl scripts. The following commands are used to read and write design data. +read_lef [-tech] [-library] filename +read_def filename +write_def [-version 5.8|5.7|5.6|5.5|5.4|5.3] filename +read_verilog filename +write_verilog filename +read_db filename +write_db filename +write_abstract_lef filename" +"What do these Debug output mean? +[INFO MPL-0024] [Multilevel Autoclustering] Creating clustered netlist. +[INFO MPL-0039] [Coarse Shaping] Determining shape functions for clusters. +[INFO MPL-0028] [Hierarchical Macro Placement] Placing clusters and macros. +[INFO MPL-0037] Updated location of 95 macros +Delete buffers for RTLMP flow... +[INFO RSZ-0026] Removed 0 buffers.","Messages with the MPL prefix are from the macro placement (mpl) module. These messages are progress messages, informing the user which step of the HierRTLMP flow is being executed." \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.xlsx new file mode 100644 index 0000000..d7227cf Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/General/General.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/README.md b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/README.md new file mode 100644 index 0000000..823a3cf --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/README.md @@ -0,0 +1,7 @@ +### This is the Question-Answer format Large Language Model EDA Dataset for OpenROAD + +This dataset has been divided into 3 categories: + +1. **OR General** +2. **OR Tools** +3. **OR Flow** diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.csv b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.csv new file mode 100644 index 0000000..9ce9e17 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.csv @@ -0,0 +1,189 @@ +Prompts,Answers +What does the -switch_cell argument in PDN do while doing power switch insertion?,"During power switch insertion, the -switch_cell argument is used to specify the name of a coarse-grain power switch cell that is to be inserted wherever the standard cell rail connects to the rest of the power grid. The mesh layers are associated with the unswitched power net of the voltage domain, whereas the standard cell rail is associated with the switched power net of the voltage domain. The placement of a power switch cell connects the unswitched power mesh to the switched power rail through a power switch defined by the define_power_switch_cell command." +How does the -switch_cell argument function in PDNGEN during power switch integration?,"During power switch insertion, the -switch_cell argument is used to specify the name of a coarse-grain power switch cell that is to be inserted wherever the standard cell rail connects to the rest of the power grid. The mesh layers are associated with the unswitched power net of the voltage domain, whereas the standard cell rail is associated with the switched power net of the voltage domain. The placement of a power switch cell connects the unswitched power mesh to the switched power rail through a power switch defined by the define_power_switch_cell command." +What does the -switch_cell argument in PDN do while doing power switch insertion?,"For inserting power switches, the -switch_cell parameter is utilized to denote a coarse-grain power switch cell's name for insertion at points where the standard cell rail merges with the broader power grid. The mesh layers correspond with the voltage domain's unswitched power net, and the standard cell rail links to the switched power net. Inserting a power switch cell bridges the unswitched power mesh and the switched power rail, facilitated by the define_power_switch_cell command." +What does the par module do?,"The partitioning module (par) is based on TritonPart, an open-source constraints-driven partitioner. par can be used to partition a hypergraph or a gate-level netlist. TritonPart solves multi-way partitioning by 1) constraints-driven coarsening, 2) initial partitioning, 3) refinement, 4) cut-overlay clustering and partitioning (COCP), and 5) V-cycle refinement. The purpose of partitioning a netlist is to reduce the complexity of a circuit so that algorithms can operate on smaller chunks of the netlist at a time. Partitioning a netlist may slightly reduce the optimization opportunities compared to a non-partitioned approach, but it greatly benefits the runtime. Partitioning a netlist may be the only option to feasibly operate on very large circuits." +What functionality does the par module provide?,"The partitioning module (par) is based on TritonPart, an open-source constraints-driven partitioner. par can be used to partition a hypergraph or a gate-level netlist. TritonPart solves multi-way partitioning by 1) constraints-driven coarsening, 2) initial partitioning, 3) refinement, 4) cut-overlay clustering and partitioning (COCP), and 5) V-cycle refinement. The purpose of partitioning a netlist is to reduce the complexity of a circuit so that algorithms can operate on smaller chunks of the netlist at a time. Partitioning a netlist may slightly reduce the optimization opportunities compared to a non-partitioned approach, but it greatly benefits the runtime. Partitioning a netlist may be the only option to feasibly operate on very large circuits." +What does the par module do?,"The partitioning tool, par, leverages TritonPart, a freely available constraint-based partitioning software. It enables the partitioning of hypergraphs or gate-level netlists through a process involving constraint-led coarsening, initial partitioning, refinement, cut-overlay clustering and partitioning (COCP), and V-cycle refinement. The main goal is to simplify the circuit's complexity, allowing algorithms to manage smaller sections of the netlist efficiently. Though partitioning may slightly limit optimization chances, it significantly enhances runtime and is often the sole strategy for managing vast circuits." +Is TritonRoute the foundation of drt?,"The Detailed Routing (drt) module in OpenROAD is based on the open-source detailed router TritonRoute. TritonRoute consists of several main building blocks, including pin access analysis, track assignment, initial detailed routing, search and repair, and a DRC engine. The initial development of the router is inspired by the ISPD-2018 initial detailed routing contest. However, the current drt framework differs and is built from scratch, aiming for an industrial-oriented, scalable, and flexible flow." +Does TritonRoute serve as the underlying technology for drt?,"The Detailed Routing (drt) module in OpenROAD is based on the open-source detailed router TritonRoute. TritonRoute consists of several main building blocks, including pin access analysis, track assignment, initial detailed routing, search and repair, and a DRC engine. The initial development of the router is inspired by the ISPD-2018 initial detailed routing contest. However, the current drt framework differs and is built from scratch, aiming for an industrial-oriented, scalable, and flexible flow." +Is TritonRoute the foundation of drt?,"The Detailed Routing (drt) module of OpenROAD, founded on the open-source detailed router TritonRoute, incorporates key components like pin access analysis, track assignment, initial routing, search and repair, and a DRC (Design Rule Checking) engine. Initially inspired by the ISPD-2018 detailed routing challenge, the current drt architecture is entirely new, designed for industrial-grade scalability and flexibility." +"What do these Debug output mean? +[INFO MPL-0024] [Multilevel Autoclustering] Creating clustered netlist. +[INFO MPL-0039] [Coarse Shaping] Determining shape functions for clusters. +[INFO MPL-0028] [Hierarchical Macro Placement] Placing clusters and macros. +[INFO MPL-0037] Updated location of 95 macros +Delete buffers for RTLMP flow... +[INFO RSZ-0026] Removed 0 buffers.","Messages with the MPL prefix are from the macro placement (mpl) module. These messages are progress messages, informing the user which step of the HierRTLMP flow is being executed." +What are the units of the -pad_right and -pad_left arguments of the global_placement function,"In global_placement, -pad_right and -pad_left add padding which is measured in cell sites to effectively make the cell appear wider. pad_left adds a pad to the left side, pad_right adds it to the right side. Wider cells during global placement can help reduce placement congestion and make finding a valid placement easier." +What are the measurement units for the -pad_right and -pad_left arguments in the global_placement function?,"In global_placement, -pad_right and -pad_left add padding which is measured in cell sites to effectively make the cell appear wider. pad_left adds a pad to the left side, pad_right adds it to the right side. Wider cells during global placement can help reduce placement congestion and make finding a valid placement easier." +What are the units of the -pad_right and -pad_left arguments of the global_placement function,"In the global placement process, the options -pad_right and -pad_left introduce padding in terms of cell sites, effectively broadening the cell. This padding on either side aids in alleviating placement congestion and facilitates easier placement validation." +Does space padding influence the design utilization? I feel like it shouldn't.,"Cell padding only impacts the way the global placer (gpl) and detailed placer (dpl) sees the cells. Cell padding does not change the logic area of the cell from the user perspective. If you were to use the report_design_area command, you would see the unpadded design utilization reported." +"Does padding affect design utilization, in your opinion?","Cell padding only impacts the way the global placer (gpl) and detailed placer (dpl) sees the cells. Cell padding does not change the logic area of the cell from the user perspective. If you were to use the report_design_area command, you would see the unpadded design utilization reported." +Does space padding influence the design utilization? I feel like it shouldn't.,"Padding adjustments affect only how global and detailed placers view the cells, leaving the cell's logical area as perceived by the user unchanged. Utilizing the report_design_area command will display the design's utilization without the padding." +"Wouldn't manually adding pads in the global_placement function reduce the maximum design utilization possible for a design? Especially since OpenROAD wants to be automatic, GPL will stop everything if it sees a DU >100% even if it could achieve a reasonable DU with equivalent padding","Cell padding can reduce the maximum possible design utilization. If you don't want padding in your design, you can reduce the default padding or turn it off. However, padding is usually necessary to achieve a cleanly routed design, because cells which are too close together may make routing impossible. If you want to optimize for very high-density designs, I believe you can also set padding on a master-by-master basis so that only the most difficult cells are padded. This process may take some trial and error." +Could manually adding pads in the global_placement function affect the maximum design utilization?,"Cell padding can reduce the maximum possible design utilization. If you don't want padding in your design, you can reduce the default padding or turn it off. However, padding is usually necessary to achieve a cleanly routed design, because cells which are too close together may make routing impossible. If you want to optimize for very high-density designs, I believe you can also set padding on a master-by-master basis so that only the most difficult cells are padded. This process may take some trial and error." +"Wouldn't manually adding pads in the global_placement function reduce the maximum design utilization possible for a design? Especially since OpenROAD wants to be automatic, GPL will stop everything if it sees a DU >100% even if it could achieve a reasonable DU with equivalent padding","Implementing cell padding may limit the maximum design utilization achievable. Adjusting or disabling default padding is an option, though padding is often crucial for achieving a neatly routed design by preventing overly congested cell placements. For high-density design optimization, padding can be selectively applied to particularly challenging cells, requiring some experimentation." +Why did I encounter an issue with CORE_UTILIZATION when trying to aim for a DU of 70% on the ASAP7 PDK which should be possible and reasonable for any design?,"If you are using ORFS, the CORE_UTILIZATION variable only determines the core utilization after Yosys (synthesis) runs using the netlist data. The utilization can change dramatically as OpenROAD performs timing optimization, which will insert buffers, remove buffers, and resize cells. For example, if you set CORE_UTILIZATION to 70% utilization during the initialization step, you may end up with 90%+ utilization because of optimization to meet timing constraints. It is currently up to the designer to ensure that the CORE_UTILIZATION is set appropriately, which may require some trial and error." +Why did I face a CORE_UTILIZATION issue when targeting a DU of 70% with the ASAP7 PDK?,"If you are using ORFS, the CORE_UTILIZATION variable only determines the core utilization after Yosys (synthesis) runs using the netlist data. The utilization can change dramatically as OpenROAD performs timing optimization, which will insert buffers, remove buffers, and resize cells. For example, if you set CORE_UTILIZATION to 70% utilization during the initialization step, you may end up with 90%+ utilization because of optimization to meet timing constraints. It is currently up to the designer to ensure that the CORE_UTILIZATION is set appropriately, which may require some trial and error." +Why did I encounter an issue with CORE_UTILIZATION when trying to aim for a DU of 70% on the ASAP7 PDK which should be possible and reasonable for any design?,"With ORFS, the CORE_UTILIZATION variable reflects core utilization post-Yosys synthesis, based on netlist data. Subsequent timing optimization in OpenROAD, which includes buffer insertion, deletion, and cell resizing, can significantly alter utilization levels. Designers must judiciously set CORE_UTILIZATION, anticipating possible adjustments through trial and error." +"If I have a design for which the detailed placement fails for a few instances, if I relax my timing constraints will it result in a successful placement?","Relaxing timing constraints can usually reduce your design utilization because fewer buffers will need to be inserted. However, detailed placement can fail for several reasons, including 1) setting core utilization too high, 2) not having enough cell padding during global placement, 3) having too much cell padding during detailed placement, 4) having a poor macro placement which will block placement of some standard cells" +"If detailed placement fails for certain instances in my design, would loosening timing constraints help achieve placement?","Relaxing timing constraints can usually reduce your design utilization because fewer buffers will need to be inserted. However, detailed placement can fail for several reasons, including 1) setting core utilization too high, 2) not having enough cell padding during global placement, 3) having too much cell padding during detailed placement, 4) having a poor macro placement which will block placement of some standard cells" +"If I have a design for which the detailed placement fails for a few instances, if I relax my timing constraints will it result in a successful placement?","Easing timing constraints can lead to lower design utilization by reducing the need for buffer insertion. However, detailed placement might fail due to reasons like excessive core utilization, insufficient global placement padding, excessive detailed placement padding, or suboptimal macro placement impeding standard cell placement." +"The timing optimizations done by the synthesis tool are ""discarded"" as the buffers are removed?","Empiracally, the OpenROAD team has found that OpenROAD optimizes better when the buffers from Yosys are removed, because Yosys does not do physical synthesis." +Are the timing adjustments made by the synthesis tool lost when buffers are eliminated?,"Empiracally, the OpenROAD team has found that OpenROAD optimizes better when the buffers from Yosys are removed, because Yosys does not do physical synthesis." +"The timing optimizations done by the synthesis tool are ""discarded"" as the buffers are removed?","The OpenROAD team has empirically observed that removing Yosys-inserted buffers leads to better optimization outcomes, as Yosys lacks physical synthesis capabilities." +Is there no need to re-synthesize with different timing constraints with Yosys? Or does it also use different/bigger non-buffer cells that also need to be resized?,"Empirically, applying timing constraints to Yosys for synthesis does not have much impact on the output netlist. However, the results may not be identical if the timing constraints are changed." +"Is re-synthesizing with altered timing constraints unnecessary with Yosys, or does it also resize non-buffer cells?","Empirically, applying timing constraints to Yosys for synthesis does not have much impact on the output netlist. However, the results may not be identical if the timing constraints are changed." +Is there no need to re-synthesize with different timing constraints with Yosys? Or does it also use different/bigger non-buffer cells that also need to be resized?,"Applying timing constraints during Yosys synthesis shows limited influence on the netlist outcome, with possible variations if timing constraints are altered." +"What does this warning mean? +[WARNING ODB-0208] VIA: duplicate VIA (via5_6_120_288_1_2_58_322) ignored...","This warning likely occurs because of multiple block abstracts with the same via. To fix this problem, one should ensure that the block abstracts do not have duplicates via definitions." +"Upon attempting to read an invalid ODB file, OpenROAD doesn't attempt to validate it and instead crashes with a cryptic message of Error: read_db.tcl, 1 ios_base::clear: unspecified iostream_category error. Why is this happening?","I would advise against using low-level OBD APIs to interact with OpenROAD. User-facing APIs in OpenROAD have documentation and error checking to prevent improper usage, however low-level APIs may not have error checking for performance reasons. In this case, it appears the db you are creating does not have a logger and can't issue any messages." +Why does OpenROAD crash without attempting to validate an invalid ODB file?,"I would advise against using low-level OBD APIs to interact with OpenROAD. User-facing APIs in OpenROAD have documentation and error checking to prevent improper usage, however low-level APIs may not have error checking for performance reasons. In this case, it appears the db you are creating does not have a logger and can't issue any messages." +"Upon attempting to read an invalid ODB file, OpenROAD doesn't attempt to validate it and instead crashes with a cryptic message of Error: read_db.tcl, 1 ios_base::clear: unspecified iostream_category error. Why is this happening?","I recommend against using the low-level OBD APIs in OpenROAD since user-friendly APIs offer documentation and error checking to prevent misuse, unlike low-level APIs that might lack error checks for efficiency. In your situation, the database being created lacks a logger, preventing message issuance." +What is IR Drop Analysis?,"The IR Drop Analysis module in OpenROAD (psm) is based on PDNSim, an open-source static IR analyzer. PDNSim will perform a simulation based on the estimated current draw of each instance to estimate what is the voltage drop seen at each cell. That is, it shows the voltage drop between the voltage source(s) of the chip and each instance." +Can you explain IR Drop Analysis and its purposes?,"The IR Drop Analysis module in OpenROAD (psm) is based on PDNSim, an open-source static IR analyzer. PDNSim will perform a simulation based on the estimated current draw of each instance to estimate what is the voltage drop seen at each cell. That is, it shows the voltage drop between the voltage source(s) of the chip and each instance." +What is IR Drop Analysis?,"The IR Drop Analysis module in OpenROAD, based on PDNSim, performs simulations to estimate the voltage drop across each cell by analyzing the current draw of each instance, illustrating the drop from the chip's voltage source(s) to each instance." +What are the features of IR Drop analysis?,"The features of IR Drope analysis are: reporting the worst IR drop, reporting the worst current density over all nodes and wire segments in the power distribution network (given a placed and PDN-synthesized design), checking for floating PDN stripes on the power and ground nets, and spice netlist writer for power distribution network wire segments." +What characteristics define IR Drop analysis?,"The features of IR Drope analysis are: reporting the worst IR drop, reporting the worst current density over all nodes and wire segments in the power distribution network (given a placed and PDN-synthesized design), checking for floating PDN stripes on the power and ground nets, and spice netlist writer for power distribution network wire segments." +What are the features of IR Drop analysis?,"IR Drop analysis features include identifying the most severe IR drop and current density across all nodes and wire segments of the power distribution network, detecting floating PDN stripes on power and ground nets, and generating spice netlists for PDN wire segments." +What is Flute3?,Flute3 is an open-source rectilinear Steiner minimum tree heuristic with improvements made by UFRGS students and James Cherry. This tool is used for the calculation of wirelength in grt and rsz. +What distinguishes Flute3?,Flute3 is an open-source rectilinear Steiner minimum tree heuristic with improvements made by UFRGS students and James Cherry. This tool is used for the calculation of wirelength in grt and rsz. +What is Flute3?,"Flute3, enhanced by UFRGS students and James Cherry, is an open-source heuristic for calculating the rectilinear Steiner minimum tree, crucial for estimating wirelength in tools like grt and rsz." +What does the global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The global_connect command is used to define logical connections between supply pins on design instances and their respective supply nets. Note that the global_connect command only creates a logical connection; it does not perform any routing for a physical connection. +What function does the global_connect command serve?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The global_connect command is used to define logical connections between supply pins on design instances and their respective supply nets. Note that the global_connect command only creates a logical connection; it does not perform any routing for a physical connection. +What does the global_connect command do?,"Global connections are designated for linking supply nets to cell supply pins without establishing physical routes, instead creating logical connections that are made using the global_connect command." +What does the clear_global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The clear_global_connect command is used to clear previously declared connections between supply pins on design instances and their respective supply nets. Note that the clear_global_connect command only clears the logical connections; it does not remove any routing or physical connections. +What is the effect of using the clear_global_connect command?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The clear_global_connect command is used to clear previously declared connections between supply pins on design instances and their respective supply nets. Note that the clear_global_connect command only clears the logical connections; it does not remove any routing or physical connections. +What does the clear_global_connect command do?,The clear_global_connect command removes logical connections between supply pins and their nets without affecting any physical routing or connections. +What does the report_global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The report_global_connect command is used to print out the currently defined global connection rules. +What information does the report_global_connect command provide?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The report_global_connect command is used to print out the currently defined global connection rules. +What does the report_global_connect command do?,"Global connections typically link supply nets to cell supply pins, and the report_global_connect command prints the existing global connection rules." +What does the report_cell_usage command do?,The report_cell_usage command is used to print out the number of instances of each type of cell (master) used in the design. +How does the report_cell_usage command assist users?,The report_cell_usage command is used to print out the number of instances of each type of cell (master) used in the design. +What does the report_cell_usage command do?,The report_cell_usage command displays the count of each cell type used within the design. +Is SystemVerilog support limited to the constructs that Yosys supports?,The OpenROAD Flow is limited to the RTL language support that the Yosys synthesizer provides. Yosys currently provides support for a limited subset of SystemVerilog and full support for Verilog. OpenROAD only supports structural Verilog netlists. +Are there limitations to SystemVerilog support based on Yosys compatibility?,The OpenROAD Flow is limited to the RTL language support that the Yosys synthesizer provides. Yosys currently provides support for a limited subset of SystemVerilog and full support for Verilog. OpenROAD only supports structural Verilog netlists. +Is SystemVerilog support limited to the constructs that Yosys supports?,"OpenROAD's RTL language support is contingent on Yosys synthesizer's capabilities, with full support for Verilog and partial support for SystemVerilog." +What is the job of Pin Placer?,"Place pins on the boundary of the die on the track grid to minimize net wirelengths. Pin placement also creates a metal shape for each pin using min-area rules. For designs with unplaced cells, the net wirelength is computed considering the center of the die area as the unplaced cells' position." +What is the function of the Pin Placer tool?,"Place pins on the boundary of the die on the track grid to minimize net wirelengths. Pin placement also creates a metal shape for each pin using min-area rules. For designs with unplaced cells, the net wirelength is computed considering the center of the die area as the unplaced cells' position." +What is the job of Pin Placer?,"For minimized net wirelengths, place pins on the die's boundary on the track grid, creating metal shapes for each pin according to min-area rules and considering the die center as the position for unplaced cells." +What is RePlAce in OpenROAD?,"RePlAce is a tool for advancing solution quality and routability validation in Global Placement. Its features are analytic and nonlinear placement algorithms. it solves electrostatic force equations using Nesterov's method, verified with various commercial technologies and research enablements using OpenDB, verified deterministic solution generation with various compilers and OS, and supports Mixed-size placement mode." +What is RePlAce and its function in OpenROAD?,"RePlAce is a tool for advancing solution quality and routability validation in Global Placement. Its features are analytic and nonlinear placement algorithms. it solves electrostatic force equations using Nesterov's method, verified with various commercial technologies and research enablements using OpenDB, verified deterministic solution generation with various compilers and OS, and supports Mixed-size placement mode." +What is RePlAce in OpenROAD?,"RePlAce advances global placement solution quality and routability with analytic and nonlinear algorithms, solving electrostatic force equations and ensuring deterministic solutions across various technologies." +What is Hierarchical Macro Placement/ Hier-RTLMP?,"""Hier-RTLMP"" is defined as a hierarchical automatic macro placer for large-scale complex IP blocks. This tool builds on the existing RTLMP (mpl) framework, adopting a multilevel physical planning approach that exploits the hierarchy and data flow inherent in the design RTL." +How is Hierarchical Macro Placement defined within OpenROAD?,"""Hier-RTLMP"" is defined as a hierarchical automatic macro placer for large-scale complex IP blocks. This tool builds on the existing RTLMP (mpl) framework, adopting a multilevel physical planning approach that exploits the hierarchy and data flow inherent in the design RTL." +What is Hierarchical Macro Placement/ Hier-RTLMP?,"Hier-RTLMP, building on the RTLMP framework, is a hierarchical macro placer leveraging design RTL's inherent hierarchy and data flow for complex IP blocks." +What file formats are supported by Parallax Static Timing Analyzer or OpenSTA?,"The Following standard file formats are supported by Parallax Static Timing Analyzer or OpenSTA: Verilog netlist, Liberty library, SDC timing constraints,SDF delay annotation, and SPEF parasitics." +Which file formats does Parallax Static Timing Analyzer accept?,"The Following standard file formats are supported by Parallax Static Timing Analyzer or OpenSTA: Verilog netlist, Liberty library, SDC timing constraints,SDF delay annotation, and SPEF parasitics." +What file formats are supported by Parallax Static Timing Analyzer or OpenSTA?,"OpenSTA supports Verilog netlist, Liberty library, SDC timing constraints, SDF delay annotation, and SPEF parasitics for timing verification." +"`auto_place_pins pin_layer` places pins on a single layer but It should be able to place vertical pins (sides of the die) and horizontal pins (top and bottom of the die) in separate layers, why is it not able to do this?","I currently recommend using `io_placer` instead of `auto_place_pins`. Here's an example:```io_placer -hor_layer 3 -ver_layer 2```Note that `io_placer` uses cell placement information to guide the I/O pin placement. If placement has not yet been run, the `-random` flag is required, which will distribute the pins evenly over the die boundary." +Why can't auto_place_pins pin_layer place pins on separate layers for vertical and horizontal orientations?,"I currently recommend using `io_placer` instead of `auto_place_pins`. Here's an example:```io_placer -hor_layer 3 -ver_layer 2```Note that `io_placer` uses cell placement information to guide the I/O pin placement. If placement has not yet been run, the `-random` flag is required, which will distribute the pins evenly over the die boundary." +"`auto_place_pins pin_layer` places pins on a single layer but It should be able to place vertical pins (sides of the die) and horizontal pins (top and bottom of the die) in separate layers, why is it not able to do this?","For pin placement, io_placer is recommended over auto_place_pins, using layer specifications for guided I/O pin placement or the -random flag for preliminary placement before cell placement." +Tell me about the parts of DFT insertion?,"A simple DFT insertion consists of the following parts: a scan_in pin where the test patterns are shifted in, a scan_out pin where the test patterns are read from, scan cells that replace flops with registers that allow for testing, one or more scan chains (shift registers created from your scan cells), a scan_enable pin to allow your design to enter and leave the test mode." +Could you describe the components involved in DFT insertion?,"A simple DFT insertion consists of the following parts: a scan_in pin where the test patterns are shifted in, a scan_out pin where the test patterns are read from, scan cells that replace flops with registers that allow for testing, one or more scan chains (shift registers created from your scan cells), a scan_enable pin to allow your design to enter and leave the test mode." +Tell me about the parts of DFT insertion?,"DFT insertion typically involves a scan_in pin for inputting test patterns, a scan_out pin for outputting test patterns, scan cells that are substituted for flops, one or more scan chains forming shift registers, and a scan_enable pin for toggling test mode on and off." +What is Metal fill?,"Metal filling is a common process in integrated circuit design to enhance manufacturability and yield by making the density of metal shapes more uniform across the design. In OpenROAD, the Finale module (fin) inserts floating metal fill shapes to meet metal density design rules while obeying DRC constraints. The rules for generating metal fill shapes are driven by a JSON configuration file, and the schema can be found in the OpenROAD documentation." +What is the purpose of Metal fill in OpenROAD?,"Metal filling is a common process in integrated circuit design to enhance manufacturability and yield by making the density of metal shapes more uniform across the design. In OpenROAD, the Finale module (fin) inserts floating metal fill shapes to meet metal density design rules while obeying DRC constraints. The rules for generating metal fill shapes are driven by a JSON configuration file, and the schema can be found in the OpenROAD documentation." +What is Metal fill?,"Metal filling, used to improve manufacturability and yield in IC design by standardizing metal shape density, is implemented in OpenROAD's Finale module. It places non-connecting metal fill shapes in accordance with metal density rules and Design Rule Checking (DRC) constraints, guided by a JSON configuration file detailed in the OpenROAD documentation." +What are the Gate Resizer commands?,The resizer commands stop when the design area is -max_utilization util percent of the core area. util is between 0 and 100. The resizer stops and reports an error if the maximum utilization is exceeded. +What are the functionalities of the Gate Resizer commands?,The resizer commands stop when the design area is -max_utilization util percent of the core area. util is between 0 and 100. The resizer stops and reports an error if the maximum utilization is exceeded. +What are the Gate Resizer commands?,"The resizer tool halts if the design exceeds -max_utilization percent of the core area's utilization, throwing an error if the limit is surpassed." +What is macro placement?,"The macro placement module in OpenROAD (mpl) is based on TritonMacroPlacer, an open-source ParquetFP-based macro cell placer. The macro placer places macros/blocks honoring halos, channels, and cell row ""snapping"". Run global_placement before macro placement." +What is macro placement and its significance in OpenROAD?,"The macro placement module in OpenROAD (mpl) is based on TritonMacroPlacer, an open-source ParquetFP-based macro cell placer. The macro placer places macros/blocks honoring halos, channels, and cell row ""snapping"". Run global_placement before macro placement." +What is macro placement?,"The macro placement module in OpenROAD, built on TritonMacroPlacer, places macros/blocks while respecting design constraints like halos, channels, and cell row alignment. It's recommended to run global_placement prior to macro placement." +Elaborate on FastRoute?,"FastRoute is a global routing tool for VLSI back-end design. It is based on sequential rip-up and re-route (RRR) and a lot of novel techniques. FastRoute 1.0 first uses FLUTE to construct congestion-driven Steiner trees, which will later undergo the edge-shifting process to optimize tree structure to reduce congestion. It then uses pattern routing and maze routing with a logistic function-based cost function to solve the congestion problem. FastRoute 2.0 proposed monotonic routing and multi-source multi-sink maze routing techniques to enhance the capability to reduce congestion. FastRoute 3.0 introduced the virtual capacity technique to adaptively change the capacity associated with each global edge to divert wire usage from highly congested regions to less congested regions. FastRoute 4.0 proposed via-aware Steiner tree, 3-bend routing, and a delicate layer assignment algorithm to effectively reduce via count while maintaining outstanding congestion reduction capability. FastRoute 4.1 simplifies the way the virtual capacities are updated and applies a single set of tuning parameters to all benchmark circuits" +How does FastRoute enhance routing processes?,"FastRoute is a global routing tool for VLSI back-end design. It is based on sequential rip-up and re-route (RRR) and a lot of novel techniques. FastRoute 1.0 first uses FLUTE to construct congestion-driven Steiner trees, which will later undergo the edge-shifting process to optimize tree structure to reduce congestion. It then uses pattern routing and maze routing with a logistic function-based cost function to solve the congestion problem. FastRoute 2.0 proposed monotonic routing and multi-source multi-sink maze routing techniques to enhance the capability to reduce congestion. FastRoute 3.0 introduced the virtual capacity technique to adaptively change the capacity associated with each global edge to divert wire usage from highly congested regions to less congested regions. FastRoute 4.0 proposed via-aware Steiner tree, 3-bend routing, and a delicate layer assignment algorithm to effectively reduce via count while maintaining outstanding congestion reduction capability. FastRoute 4.1 simplifies the way the virtual capacities are updated and applies a single set of tuning parameters to all benchmark circuits" +Elaborate on FastRoute?,"FastRoute utilizes a series of innovative techniques for global routing, including FLUTE for constructing congestion-driven Steiner trees, edge-shifting, pattern routing, and maze routing to address congestion, with further enhancements in subsequent versions to reduce congestion and via count effectively." +"Is there any way I can use just the RTL-MP2 stand-alone on either an RTL design or a gate netlist? The issue is, that we use proprietary tools so do not have an OpenDB database for our designs.","OpenROAD supports interoperability with other EDA tools through the industry standard Verilog, LEF, and DEF formats. In this case, you can import a DEF file into OpenROAD from an external tool, run RTL-MP2, and then export the DEF file. The DEF file format should be supported by nearly all EDA physical design tools." +Is it possible to use RTL-MP2 standalone for RTL designs or gate netlists without an OpenDB database?,"OpenROAD supports interoperability with other EDA tools through the industry standard Verilog, LEF, and DEF formats. In this case, you can import a DEF file into OpenROAD from an external tool, run RTL-MP2, and then export the DEF file. The DEF file format should be supported by nearly all EDA physical design tools." +"Is there any way I can use just the RTL-MP2 stand-alone on either an RTL design or a gate netlist? The issue is, that we use proprietary tools so do not have an OpenDB database for our designs.","OpenROAD facilitates interoperability with other EDA tools through standard formats like Verilog, LEF, and DEF, allowing for seamless DEF file imports and exports to and from external tools." +How do I check DRC?,"In OpenROAD, you can use the check_drc command to run the design rule check (DRC). It should be noted that check_drc is not a general-purpose checker and only verifies signal routing according to routing rules from the technology LEF file. check_drc also requires routing guides in order to run, so global routing must be performed first. DRC is also commonly performed by an external tool which will check all layers, not just the metal routing layers." +How do I perform a DRC check in OpenROAD?,"In OpenROAD, you can use the check_drc command to run the design rule check (DRC). It should be noted that check_drc is not a general-purpose checker and only verifies signal routing according to routing rules from the technology LEF file. check_drc also requires routing guides in order to run, so global routing must be performed first. DRC is also commonly performed by an external tool which will check all layers, not just the metal routing layers." +How do I check DRC?,"The check_drc command in OpenROAD performs design rule checks based on routing rules from the technology LEF file, requiring prior global routing and typically supplemented by external tools for comprehensive DRC across all layers." +What does the argument -floorplan_initialize do in read_def?,"When using the read_def command with the -floorplan_initialize argument, OpenROAD will read only physical placement information such as pin locations and instance locations. It does not read or redefine the netlist." +What does the -floorplan_initialize argument achieve in read_def?,"When using the read_def command with the -floorplan_initialize argument, OpenROAD will read only physical placement information such as pin locations and instance locations. It does not read or redefine the netlist." +What does the argument -floorplan_initialize do in read_def?,"Using the read_def command with -floorplan_initialize in OpenROAD loads only the physical placement data, excluding netlist alterations." +What does the argument -skip_pin_swap & -skip_gate_cloning do in repair_timing?,"These flags disable optimizations in case of trouble or unexpected results. They are mainly included as a failsafe for users, rather than something that is expected to be used." +What are the functions of -skip_pin_swap & -skip_gate_cloning in repair_timing?,"These flags disable optimizations in case of trouble or unexpected results. They are mainly included as a failsafe for users, rather than something that is expected to be used." +What does the argument -skip_pin_swap & -skip_gate_cloning do in repair_timing?,"Certain flags in OpenROAD disable optimizations as a safeguard against unexpected outcomes, intended as a last resort for troubleshooting." +What does the detailed_placement command do in OpenROAD?,"The detailed_placement command moves instances to legal locations after global placement. While the global placer (gpl) may place cells in a roughly optimal position, gpl may not place the cells in legal locations because they may not be aligned to cell rows or sites. The detailed placer (dpl) will legalize the cell by shifting it to a nearby location which is aligned to the cell site grid. The detailed_placement command only performs basic legalization and does not attempt to optimize placement. The optimize_mirroring and improve_placement commands will perform optimization on the legalized cells." +What is the purpose of the detailed_placement command?,"The detailed_placement command moves instances to legal locations after global placement. While the global placer (gpl) may place cells in a roughly optimal position, gpl may not place the cells in legal locations because they may not be aligned to cell rows or sites. The detailed placer (dpl) will legalize the cell by shifting it to a nearby location which is aligned to the cell site grid. The detailed_placement command only performs basic legalization and does not attempt to optimize placement. The optimize_mirroring and improve_placement commands will perform optimization on the legalized cells." +What does the detailed_placement command do in OpenROAD?,"The detailed_placement command in OpenROAD repositions instances to legal sites post-global placement, focusing on basic legalization without attempting placement optimization, which is handled by subsequent commands." +"What does the argument -max_displacement disp|{disp_x disp_y} do in detailed_placement +Command?","Max distance that an instance can be moved (in microns) when finding a site where it can be placed. Either set one value for both directions or set {disp_x disp_y} for individual directions. The default values are {0, 0}, and the allowed values within are integers [0, MAX_INT]. This argument is useful because it limits the amount of searching and therefore amount of runtime that the detailed placer can use." +How does the -max_displacement argument affect the detailed_placement command?,"Max distance that an instance can be moved (in microns) when finding a site where it can be placed. Either set one value for both directions or set {disp_x disp_y} for individual directions. The default values are {0, 0}, and the allowed values within are integers [0, MAX_INT]. This argument is useful because it limits the amount of searching and therefore amount of runtime that the detailed placer can use." +"What does the argument -max_displacement disp|{disp_x disp_y} do in detailed_placement +Command?","Specifies the maximum distance instances can be relocated during detailed placement, with default settings at {0, 0} and customizable values for x and y directions to limit search scope and runtime." +What does the argument -disallow_one_site_gaps do in the detailed_placement command?,"detailed_place -disallow_one_site_gaps will disallow the detailed placer from leaving gaps between cells that are exactly one cell sitewide. This feature is mainly useful for PDKs that do not have filler cells which are one site-wide. In this case, one-site-wide gaps are unfillable and will cause DRC violations." +What does the -disallow_one_site_gaps argument do in detailed_placement?,"detailed_place -disallow_one_site_gaps will disallow the detailed placer from leaving gaps between cells that are exactly one cell sitewide. This feature is mainly useful for PDKs that do not have filler cells which are one site-wide. In this case, one-site-wide gaps are unfillable and will cause DRC violations." +What does the argument -disallow_one_site_gaps do in the detailed_placement command?,"The detailed_place -disallow_one_site_gaps option prevents one-site-wide gaps between cells in detailed placement, addressing DRC issues in PDKs lacking one-site-wide filler cells." +What does the argument -report_file_name do in the detailed_placement command?,"The -report_file_name argument for the detailed_placement command specifies where the report for detailed placement should be saved. The report is saved in the JSON format and contains metrics related to detailed_placement. If this argument is not provided, no report will be saved for the detailed_placement command." +What role does the -report_file_name argument play in the detailed_placement command?,"The -report_file_name argument for the detailed_placement command specifies where the report for detailed placement should be saved. The report is saved in the JSON format and contains metrics related to detailed_placement. If this argument is not provided, no report will be saved for the detailed_placement command." +What does the argument -report_file_name do in the detailed_placement command?,"The detailed_placement command's -report_file_name argument designates the storage location for the placement report in JSON format, detailing metrics of the placement. Without this argument, the command does not save a report." +What does the Set Placement Padding command do?,"The set_placement_padding command sets left and right padding in multiples of the row site width. Use the set_placement_padding command before legalizing placement to leave room for routing. Use the -global flag for padding that applies to all instances. Use -instances for instance-specific padding. The instances insts can be a list of instance names, or an instance object returned by the SDC get_cells command. To specify padding for all instances of a common master, use the -filter ""ref_name == "" option to get_cells." +How does the Set Placement Padding command optimize placement?,"The set_placement_padding command sets left and right padding in multiples of the row site width. Use the set_placement_padding command before legalizing placement to leave room for routing. Use the -global flag for padding that applies to all instances. Use -instances for instance-specific padding. The instances insts can be a list of instance names, or an instance object returned by the SDC get_cells command. To specify padding for all instances of a common master, use the -filter ""ref_name == "" option to get_cells." +What does the Set Placement Padding command do?,"The set_placement_padding command adjusts the left and right padding based on row site width multiples, essential for spacing before placement legalization. It supports global padding via -global or specific instance padding through -instances, with flexibility in selecting instances via a list or the SDC get_cells command." +What is the significance of the filler_placement command?,"The filler_placement command fills gaps between detail-placed instances to connect the power and ground rails in the rows. filler_masters is a list of master/macro names to use for filling the gaps. Wildcard matching is supported, so FILL* will match, e.g., FILLCELL_X1 FILLCELL_X16 FILLCELL_X2 FILLCELL_X32 FILLCELL_X4 FILLCELL_X8. To specify a different naming prefix from FILLER_ use -prefix ." +What is the significance of the filler_placement command?,"The filler_placement command fills gaps between detail-placed instances to connect the power and ground rails in the rows. filler_masters is a list of master/macro names to use for filling the gaps. Wildcard matching is supported, so FILL* will match, e.g., FILLCELL_X1 FILLCELL_X16 FILLCELL_X2 FILLCELL_X32 FILLCELL_X4 FILLCELL_X8. To specify a different naming prefix from FILLER_ use -prefix ." +What is the significance of the filler_placement command?,The filler_placement command utilizes specified master names to fill gaps among placed instances for power and ground rail connectivity. It supports wildcard for master names selection and allows prefix customization with the -prefix option. +What is the purpose of the remove_fillers command?,This command removes all filler cells. +What does the remove_fillers command achieve?,This command removes all filler cells. +What is the purpose of the remove_fillers command?,This command clears all placed filler cells. +What does the check_placement command do?,The check_placement command checks the placement legality. It returns 0 if the placement is legal. +What does the check_placement command verify?,The check_placement command checks the placement legality. It returns 0 if the placement is legal. +What does the check_placement command do?,"The check_placement command verifies if the placement adheres to legality rules, returning 0 for a legal placement." +What does the argument -verbose in the check_placement command do?,The -verbose argument enables verbose logging in the check_placement command. +How does the -verbose argument in the check_placement command enhance its functionality?,The -verbose argument enables verbose logging in the check_placement command. +What does the argument -verbose in the check_placement command do?,Enabling the -verbose argument within the check_placement command activates detailed logging. +What does the argument -disallow_one_site_gaps in the check_placement command do?,The argument -disallow_one_site_gaps disables one site gap during placement check. +What effect does the -disallow_one_site_gaps argument have in the check_placement command?,The argument -disallow_one_site_gaps disables one site gap during placement check. +What does the argument -disallow_one_site_gaps in the check_placement command do?,The -disallow_one_site_gaps argument prevents gaps of one site in the placement legality check. +What role does this argument -report_file_name play in the check_placement command?,The argument -report_file_name in check_placement command files name for saving the report (e.g. report.json). +What information does the -report_file_name argument provide in the check_placement command?,The argument -report_file_name in check_placement command files name for saving the report (e.g. report.json). +What role does this argument -report_file_name play in the check_placement command?,"Within the check_placement command, the -report_file_name argument designates the report's filename, such as report.json." +What does the optimize_mirroring command do?,The optimize_mirroring command mirrors instances about the Y axis in a weak attempt to reduce the total half-perimeter wirelength (HPWL). No arguments are needed for this function. +What optimizations does the optimize_mirroring command perform?,The optimize_mirroring command mirrors instances about the Y axis in a weak attempt to reduce the total half-perimeter wirelength (HPWL). No arguments are needed for this function. +What does the optimize_mirroring command do?,"The optimize_mirroring command adjusts instances around the Y-axis to potentially lessen the total half-perimeter wirelength, requiring no additional arguments." +What are some useful developer commands in the detailed placement module in OpenROAD (dpl)?,"If you are a developer, you might find the following commands useful, 1. detailed_placement_debug: debug detailed placement. 2. get_masters_arg: get masters from a design. 3. get_inst_bbox: get the bounding box of an instance. 4. get_inst_grid_bbox: get the grid bounding box of an instance. 5. format_grid: format grid (takes in length x and site width w as inputs). 6. get_row_site: get row site name." +Can you list some advanced developer commands in the detailed placement module (dpl)?,"If you are a developer, you might find the following commands useful, 1. detailed_placement_debug: debug detailed placement. 2. get_masters_arg: get masters from a design. 3. get_inst_bbox: get the bounding box of an instance. 4. get_inst_grid_bbox: get the grid bounding box of an instance. 5. format_grid: format grid (takes in length x and site width w as inputs). 6. get_row_site: get row site name." +What are some useful developer commands in the detailed placement module in OpenROAD (dpl)?,"Developers might find commands like detailed_placement_debug, get_masters_arg, get_inst_bbox, get_inst_grid_bbox, format_grid, get_row_site beneficial for various debugging and configuration tasks." +What does the argument [-max_length ] do in the set_dft_config command of DFT- Design For Testing?,The argument [-max_length ] takes an integer as input for setting the maximum number of bits that can be in each scan chain. +What does the [-max_length ] argument in the set_dft_config command control?,The argument [-max_length ] takes an integer as input for setting the maximum number of bits that can be in each scan chain. +What does the argument [-max_length ] do in the set_dft_config command of DFT- Design For Testing?,The [-max_length ] argument sets a limit on the scan chain length in bits. +What does the argument [-clock_mixing] do in the set_dft_config command of DFT?,The argument [-clock_mixing] dictates how the architect mixes the scan flops based on the clock driver. The value no_mix creates scan chains with only one type of clock and edge. This may create unbalanced chains. The value clock_mix creates scan chains mixing clocks and edges. Falling edge flops are going to be stitched before the rising edge. +How does the [-clock_mixing] argument in the set_dft_config command affect DFT?,The argument [-clock_mixing] dictates how the architect mixes the scan flops based on the clock driver. The value no_mix creates scan chains with only one type of clock and edge. This may create unbalanced chains. The value clock_mix creates scan chains mixing clocks and edges. Falling edge flops are going to be stitched before the rising edge. +What does the argument [-clock_mixing] do in the set_dft_config command of DFT?,"The [-clock_mixing] argument controls the scan flops' arrangement based on the clock driver, with options for mixing or separating clock types and edges." +What does the report_dft_config command do in DFT- Design For Testing?,The report_dft_config command prints the current DFT configuration to be used by preview_dft and insert_dft. +What insights does the report_dft_config command offer in DFT- Design For Testing?,The report_dft_config command prints the current DFT configuration to be used by preview_dft and insert_dft. +What does the report_dft_config command do in DFT- Design For Testing?,The report_dft_config command outputs the current DFT setup for use in preview_dft and insert_dft. +What does the preview_dft command do in DFT- Design For Testing?,This command prints a preview of the scan chains that will be stitched by insert_dft. Use this command to iterate and try different DFT configurations. This command does not perform any modification to the design. +What preview does the preview_dft command provide in DFT- Design For Testing?,This command prints a preview of the scan chains that will be stitched by insert_dft. Use this command to iterate and try different DFT configurations. This command does not perform any modification to the design. +What does the preview_dft command do in DFT- Design For Testing?,"This command offers a glimpse into the scan chains to be established by insert_dft, allowing for DFT configuration experimentation without altering the design." +What does the argument [-verbose] do in the preview_dft command of DFT- Design For Testing?,The preview_dft command shows more information about each one of the scan chains that will be created. +How does the [-verbose] argument in the preview_dft command enhance its output?,The preview_dft command shows more information about each one of the scan chains that will be created. +What does the argument [-verbose] do in the preview_dft command of DFT- Design For Testing?,The preview_dft command provides detailed insights into the forthcoming scan chains. +What does the insert_dft command do in DFT- Design For Testing?,"The insert_dft command implements the scan chains into the design by performing the following actions: Scan Replace, Scan Architect, Scan Stitch. The result is a design with scan flops connected to form the scan chains." +What is the process of the insert_dft command in DFT- Design For Testing?,"The insert_dft command implements the scan chains into the design by performing the following actions: Scan Replace, Scan Architect, Scan Stitch. The result is a design with scan flops connected to form the scan chains." +What does the insert_dft command do in DFT- Design For Testing?,"By executing actions like Scan Replace, Scan Architect, and Scan Stitch, the insert_dft command integrates scan chains into the design." +Can you give me an example of a basic Design for Testing command?,Here is an example that will create scan chains with a max length of 10 bits mixing all the scan flops in the scan chains: set_dft_config -max_length 10 -clock_mixing clock_mix report_dft_config preview_dft -verbose insert_dft. +Could you provide a basic example of a Design for Testing command?,Here is an example that will create scan chains with a max length of 10 bits mixing all the scan flops in the scan chains: set_dft_config -max_length 10 -clock_mixing clock_mix report_dft_config preview_dft -verbose insert_dft. +Can you give me an example of a basic Design for Testing command?,An example command to create 10-bit long scan chains with mixed flops is: set_dft_config -max_length 10 -clock_mixing clock_mix report_dft_config preview_dft -verbose insert_dft. +What are the limitations of Design for Testing (DFT)?,"The limitations of DFT-Design for Testing are as follows: there are no optimizations for the scan chains, this is a WIP, there is no way to specify existing scan ports to be used by scan insertion, there is currently no way to define a user-defined scan path, and can only work with one-bit cells." +What are the known limitations of Design for Testing (DFT)?,"The limitations of DFT-Design for Testing are as follows: there are no optimizations for the scan chains, this is a WIP, there is no way to specify existing scan ports to be used by scan insertion, there is currently no way to define a user-defined scan path, and can only work with one-bit cells." +What are the limitations of Design for Testing (DFT)?,"DFT limitations include the absence of scan chain optimizations, the inability to specify existing scan ports for insertion, the lack of a method for defining custom scan paths, and compatibility only with one-bit cells." +What is the report_cts command in Clock Tree Synthesis (cst) in OpenROAD used for?,"It is used to extract metrics after a successful clock_tree_synthesis run. These metrics are the number of Clock Roots, number of Buffers Inserted, number of Clock Subnets, and number of Sinks." +What is the purpose of the report_cts command in Clock Tree Synthesis (cts) in OpenROAD?,"It is used to extract metrics after a successful clock_tree_synthesis run. These metrics are the number of Clock Roots, number of Buffers Inserted, number of Clock Subnets, and number of Sinks." +What is the report_cts command in Clock Tree Synthesis (cst) in OpenROAD used for?,"After running clock_tree_synthesis, use this to collect metrics such as the number of Clock Roots, Buffers Inserted, Clock Subnets, and Sinks." +What does the argument -out_file in report_cts command in Clock Tree Synthesis (cst) in OpenROAD do?,"The file to save cts reports. If this parameter is omitted, the report is streamed to stdout and not saved." +What does the -out_file argument in the report_cts command achieve?,"The file to save cts reports. If this parameter is omitted, the report is streamed to stdout and not saved." +What does the argument -out_file in report_cts command in Clock Tree Synthesis (cst) in OpenROAD do?,"Specifies the file for saving cts reports, defaulting to streaming to stdout if not provided." +What does the clock_tree_synthesis_debug command in Clock Tree Synthesis (cst) in OpenROAD do?,This command is an option to plot the CTS to GUI. +How does the clock_tree_synthesis_debug command assist in CST troubleshooting?,This command is an option to plot the CTS to GUI. +What does the clock_tree_synthesis_debug command in Clock Tree Synthesis (cst) in OpenROAD do?,This command allows for CTS visualization in the GUI. +What does the create_power_domain command do in upf?,This command creates power domain for a group of modules. +What does the create_power_domain command achieve in upf?,This command creates power domain for a group of modules. +What does the create_power_domain command do in upf?,Creates power domain for module groups. +What does the create_logic_port command do in upf?,"This command creates logic port. Direction must be specified from: in, out, inout." +What function does the create_logic_port command serve in upf?,"This command creates logic port. Direction must be specified from: in, out, inout." +What does the create_logic_port command do in upf?,Creates logic ports with specified directions. \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.xlsx b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.xlsx new file mode 100644 index 0000000..b29e92f Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Augmented_Data/Question-Answer/Tools/Tools.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/LICENSE b/flow-Agent/EDA-Corpus-main/LICENSE new file mode 100644 index 0000000..2f244ac --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/LICENSE @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.csv b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.csv new file mode 100644 index 0000000..d5326bc --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.csv @@ -0,0 +1,4819 @@ +code,prompt +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input2' as mentioned in the prompt +inst = block.findInst('input2') +#Set the location to coordinates (22500, 33459) +inst.setLocation(22500,33459)","Set the location of the instance named 'input2' to coordinates (22500, 33459)." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""output52"" +inst = block.findInst(""output52"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Print the net name + print(""Net:"", net.getName()) + + # Print the wire opcodes + net.printWire()",Print the wire opcode information of the the nets connecting to the instance output52 +"def get_metal_layers_and_io_top_layer(layer_name): + # Get the current block of the design + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Find the specified layer in the technology + layer = tech.findLayer(layer_name) + + # Get the upper and lower layers of the specified layer + upper_lower_layer = { + ""upper"": layer.getUpperLayer(), + ""lower"": layer.getLowerLayer() + } + + # Get the top layer of the IO Placer object of the design + iop = design.getIOPlacer() + iop_top_layer = iop.getTopLayer() + + # Return a tuple containing the upper and lower layer of the specified layer and the top layer used for the IO pin placer + return (upper_lower_layer, iop_top_layer) + +# Call the function with ""metal5"" as the argument +metal5_layers_info = get_metal_layers_and_io_top_layer(""metal5"")","Retrieve the upper and lower layers of the 'metal5' layer and encapsulate them in a dictionary with ""upper"" and ""lower"" as keys. Additionally, retrieve the setting of the top layer used for the IO pin placer. Return the results as a tuple." +"# Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'NAND2_X1' + if inst.getMaster().getName() == 'NAND2_X1': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + inst.setOrient(orient)",Vertically flip the rotation of the instances whose library cell types are 'NAND2_X1' +"# Set the rotation of the instance '_411_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'MX' +inst.setOrient('MX')",set the rotation of the instance '_411_' to 'MX' +"# Get the design block +block = ord.get_db_block() +# Get the database +db = ord.get_db() +# Get all nets +nets = block.getNets() +# Find the POWER and GROUND nets +for net in nets: + if net.getSigType() == 'POWER': + power_net = net + elif net.getSigType() == 'GROUND': + ground_net = net +# Find the source instance named ""_350_"" +source_inst = block.findInst(""_350_"") +# Find the pin connected to net ""_036_"" +for pin in source_inst.getITerms(): + if pin.getNet() is not None: + if pin.getNet().getName() == '_036_': + source_pin = pin + source_net = pin.getNet() + break +# Create a new net +new_net = odb.dbNet_create(block,'new_net_1') +# Find the master instance named 'BUF_X2' +mast = db.findMaster('BUF_X2') +# Create a new instance named 'new_inst_1' using the 'BUF_X2' master +new_inst = odb.dbInst_create(block,mast,'new_inst_1') +# Disconnect the source pin +source_pin.disconnect() +# Connect the source pin to the new net +source_pin.connect(new_net) +# Connect the pins of the new instance +for pin in new_inst.getITerms(): + if pin.isInputSignal(): + pin.connect(new_net) + elif pin.isOutputSignal(): + pin.connect(source_net) + elif pin.getSigType() == 'POWER': + pin.connect(power_net) + elif pin.getSigType() == 'GROUND': + pin.connect(ground_net) +","Add a new instance 'new_inst_1' using buffer cell BUF_X2 after the instance '_350_' on the net '_036', and connect the instances using a new net 'new_net_1'" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Disconnect the port +port.disconnect()",Disconnect the port named 'req_val' from the nets it is connected to +"# Get the current design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# Dictionary to store Capacitance Coupling Match Ratio of each net +net_cc_match_ratio = {} + +# Iterate through each net and store its Capacitance Coupling Match Ratio +for net in nets: + net_cc_match_ratio[net.getName()] = net.getCcMatchRatio() + +# List of net names to set Capacitance Coupling Match Ratio to 1 +nets = [""req_msg[13]"", ""clk""] + +# Iterate through each net name in the list and set its Capacitance Coupling Match Ratio to 1 +for net_name in nets: + net = block.findNet(net_name) + net.setCcMatchRatio(1)","Calculate the Capacitance Coupling Match Ratio for each net and organize the results into a dictionary. Use the net names as keys and their corresponding Capacitance Coupling Match Ratios as values. Additionally, ensure that the Capacitance Coupling Match Ratios for the nets named ""req_msg[13]"" and ""clk"" are set to 1." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the vias defined in the technology +vias = tech.getVias() + +# Get the Via Count of the technology +via_count = tech.getViaCount() + +# Set the Clearance Measure of the technology to 500 +print(tech.getClearanceMeasure()) + +# Create a dictionary containing vias and the count of vias +result = { + ""vias"": vias, + ""count"": via_count +}","Get the vias and via count as a dictionary with ""vias"" and ""count"" as keys, and print the Clearance Measure." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology file +layers = tech.getLayers() + +# Dictionary to store areas of layers with their names +layer_area_dict = {} + +# Iterate through each layer +for layer in layers: + # Store the area of the layer with its name in the dictionary + layer_area_dict[layer.getName()] = layer.getArea() + +# Create a result dictionary containing layer area dictionary and list of layer names +result = { + ""area_dict"": layer_area_dict, + ""layer_names"": list(layer_area_dict.keys()) +}","Retrieve the layer names defined in the technology as a list and obtain the corresponding areas of these layers of the technology, associating each area with its respective layer name in a dictionary. Return this result encapsulated in a dictionary with ""area_dict"" representing the areas of the layers and ""layer_names"" representing the list of layer names." +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the Via Count of the technology +via_count = tech.getViaCount() + +# Get the Via Generate Rules of the technology +via_rules = tech.getViaGenerateRules() + +# Get the current value of database units per micron and add 500 +db_microns = block.getDbUnitsPerMicron() + 500 + +# Set the new value of database units per micron +tech.setDbUnitsPerMicron(db_microns) + +# Create a dictionary containing via count, via rules, and the updated value of database units per micron +result = { + ""count"": via_count, + ""rules"": via_rules +}","Retrieve the via count and via generate rules of the technology. Return the result as a dictionary with ""count"" and ""rules"" as keys for the via count and via generate rules, respectively." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store rotation of the instances whose library cells are of type 'NOR2_X1' +NOR_transform_orient = {} + +# Iterate through each instance +for inst in insts: + # Check if the library cell name is ""NOR2_X1"" + if inst.getMaster().getName() == ""NOR2_X1"": + # Store the rotation of the instance + NOR_transform_orient[inst.getName()] = inst.getTransform().getOrient() + + # Check if the instance name is ""_411_"" or ""input1"" + if inst.getName() == ""_411_"" or inst.getName() == ""input1"": + # Mark the first output net of the instance + inst.getFirstOutput().getNet().setMark(True)","Get the rotation of the instances whose library cells are of type 'NOR2_X1' and return as a dict with instance name as keys, and mark the first output nets of the instances '_411_' and 'input1'." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through each instance +for inst in insts: + # Check if the master cell name contains ""NAND2_X1"" + if inst.getMaster().getName() == ""NAND2_X1"": + # Invert the instance + inst.getTransform().invert() + + # Check if the instance name is ""_411_"" or ""input1"" + if inst.getName() == ""_411_"" or inst.getName() == ""input1"": + # Get the transform of the instance + transform = inst.getTransform() + # If the orientation is 'R0', set it to 'MX'; if 'MX', set it to 'R0' + if transform.getOrient() == 'R0': + transform.setOrient('MX') + elif transform.getOrient() == 'MX': + transform.setOrient('R0')",Invert the offset and the rotation of instances whose library cells are 'NAND2_X1' and set the orient of the instance '_411_' to 'R0' if 'MX' or 'MX' if 'R0'. +"# Get the current design block +block = design.getBlock() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Set the orientation of the instance '_411_' to 'MX' +inst.getTransform().setOrient('MX') + +# Get all instances +insts = block.getInsts() + +# Dictionary to store halos of instances +inst_halos = {} + +# Iterate through each instance +for inst in insts: + # Store the halo of the instance in the inst_halos dictionary + inst_halos[inst.getName()] = inst.getHalo()",Set the orientation of the instance '_411_' to 'MX' and retrieve all the halos of instances. Return the result as a dictionary with each instance's name as the key mapped to their halo. +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Initialize lists to store non-core instances and vertical tech layers with capacitance +vertical_layers = [] +non_core_insts = [] + +# Define the direction for the layers +direction = 'VERTICAL' + +# Iterate through each instance +for inst in insts: + # Check if instance is not core instance + if not inst.getMaster().isCore(): + # Add the instance to the list of non-core instances + non_core_insts.append(inst) + +# Iterate through each layer in the technology +for layer in layers: + # Check if the layer direction is VERTICAL + if layer.getDirection() == direction: + # Add the layer and its capacitance to the list of vertical layers + vertical_layers.append((layer, layer.getCapacitance()))",Get a list of all the non-core instances and a list of the vertical layers and their capacitance as a list of tuples. +"def get_signal_types_and_endcap_status(target_instance_name, check_instance_name='_411_'): + # Get the current design block + block = design.getBlock() + + # Get all the instances + insts = block.getInsts() + + # Find the instance with the name check_instance_name + check_instance = block.findInst(check_instance_name) + + # Dictionary to store signal types in nets + signal_type_dict = {} + + # Check if check_instance is of type ENDCAP or any of its subtypes + endcap_status = check_instance.isEndCap() + print(f""End cap status of cell '{check_instance_name}':"", endcap_status) + + # Loop through all instances + for inst in insts: + # Check if any of the user flags are set to true + if inst.getUserFlag1() or inst.getUserFlag2() or inst.getUserFlag3(): + # Set the level of the instance to 1 + inst.setLevel(1) + + # Check if the instance name matches target_instance_name + if inst.getName() == target_instance_name: + # Get the nets connected to the target instance + nets = [pin.getNet() for pin in inst.getITerms()] + + # Iterate through each net + for net in nets: + # Check if the net exists + if net: + # Store the signal type of the net in the dictionary + signal_type_dict[net.getName()] = net.getSigType() + break + + # Return the dictionary containing signal types in nets + return signal_type_dict + +# Call the function to get the signal types for 'input1' and check '_411_' +signal_types = get_signal_types_and_endcap_status('input1')","Check if the library cell of instance '_411_' is type ENDCAP and get all the instances whose user flags are set and set those instances to level 1, also get the signal types in the nets of instance 'input1'" +"# Set userFlags 1 and 3 true for instance '411' and retrieve the LEQ (Logic Equivalent) information associated with the library cell of instance '411'. + +# Get the dsign block +block = design.getBlock() + +# Find the instance '411' +inst = block.findInst(""_411_"") + +# Set userFlags 1 and 3 true +inst.setUserFlag1() +inst.setUserFlag3() + +# Get the library cell of instance '411' +master = inst.getMaster() + +# Retrieve the LEQ information associated with the library cell +LEQ = master.getLEQ()",Set userFlags 1and 3 true for instance '411' and retrieves the LEQ (Logic Equivalent) information associated with the library cell of instance '411'. +"def get_and_nand_info(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Dictionary to store offsets of 'AND2_X1' instances + offset_dict_AND = {} + # Dictionary to store orientations of 'NAND2_X1' instances + orient_dict_NAND = {} + + # Iterate through instances + for inst in insts: + # Check if the master cell name is 'AND2_X1' + if inst.getMaster().getName() == ""AND2_X1"": + # Get transform and store offset + transform = inst.getTransform() + offset_dict_AND[inst.getName()] = transform.getOffset() + + # Check if the master cell name is 'NAND2_X1' + elif inst.getMaster().getName() == ""NAND2_X1"": + # Get transform and store orientation + transform = inst.getTransform() + orient_dict_NAND[inst.getName()] = transform.getOrient() + + # Return dictionaries of offsets and orientations + return offset_dict_AND, orient_dict_NAND + +# Call the function to retrieve the information +and_offsets, nand_orientations = get_and_nand_info()",Get the location of the instances whose library cell is 'AND2_X1' as a dicitonary with instance names as keys and get rotation of instance whose library cells are of type 'NAND2_X1'. +"# Set all the COVER master cells to frozen + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through instances +for inst in insts: + # Get the master of the instance + master = inst.getMaster() + # Check if the master is of type COVER + if master.isCover(): + # Set the COVER master cell to frozen so dbMTerms cannot be added or delete from the master + master.setFrozen()",set all the COVER master cells to frozen +"def get_signal_nets_and_blockages(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # List to store nets with signal type 'SIGNAL' + signal_nets = [] + + # Iterate through instances + for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate through pins + for pin in pins: + # Check if the signal type is 'SIGNAL' + if pin.getSigType() == 'SIGNAL': + # Add the net to the list + signal_nets.append(pin.getNet()) + + # Get all blockages in the block + blockages = block.getBlockages() + + # Return a tuple containing the list of nets and blockages + return (signal_nets, blockages) + +# Call the function to retrieve the information +signal_nets, blockages = get_signal_nets_and_blockages()","Get a list of all the nets of the instances whose signal type is ""SIGNAL"" and get all the blockages. Return the result as a tuple" +"# Get the design block +block =design.getBlock() + +# Reset the tapcell in the design +tapcell = design.getTapcell() +tapcell.reset() + +# Retrieve the coupling capacitance segments +coupling_segments = block.getCCSegs()",Reset the tapcell in the design and retrieve the coupling capacitance segments of the design block. +"# Get the list of hierarchical filler cell instances. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# List to store hierarchical instances with filler cells +inst_list = [] + +# Iterate through instances +for inst in insts: + # Check if the instance is hierarchical and its master is a filler cell + if inst.isHierarchical() and inst.getMaster().isFiller(): + inst_list.append(inst)",Get the list of hierarchical filler cell instances. +"def get_resistor_segments_and_hybrid_rows(): + # Get the design block + block = design.getBlock() + + # Retrieve resistor segments + resistor_segments = block.getRSegs() + + # Get the sites of rows + rows = block.getRows() + hybrid_rows = {} + + # Iterate through rows to find hybrid sites + for row in rows: + if row.getSite().isHybrid(): + hybrid_rows[row] = row.getSite() + + # Return resistor segments and hybrid rows + return (resistor_segments, hybrid_rows) + +# Call the function to get the information +resistor_segments, hybrid_rows = get_resistor_segments_and_hybrid_rows()","Get the resistor segments and a dictionary of the hybrid sites of the rows, with the row as the key and the site as the value." +"# Get source type of all the instance on level 1 with filler cells and set the placement Status of the instance 'input1' to 'UNPLACED'. + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store source types +source_dict = {} + +# Iterate through instances +for inst in insts: + # Check if the instance's master is a filler cell and it is set as level 1 + if inst.getMaster().isFiller() and inst.getLevel() == 1: + # Get and store the source type + source_dict[inst.getName()] = inst.getSourceType() + + # Check if the instance is 'input1' and set its placement status to 'UNPLACED' + if inst.getName() == ""input1"": + inst.setPlacementStatus('UNPLACED')","Get source type of all the filler cell instances set as level 1 as a dictionary with inst name as keys. Also, set the placement status flag of the instance 'input1' to 'UNPLACED'." +"def set_layer_aliases_and_get_min_spacing(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the alias of each layer + layer_alias = {} + + # Iterate through all layers + for layer in layers: + # Construct the alias using the layer index + alias = ""LayerX"" + str(layer.getNumber()) + + # Set the alias of the layer + layer.setAlias(alias) + + # Store the alias of the layer in the dictionary + layer_alias[layer.getName()] = alias + + # Get the status of USEMINSPACING for pins in LEF + min_spacing_pin = tech.getUseMinSpacingPin() + + # Return the dictionary containing the updated alias of layers and min spacing status + return { + ""Alias"": layer_alias, + ""min_spacing_pin"": min_spacing_pin + } + +# Call the function to get the results +results = set_layer_aliases_and_get_min_spacing()","Set the alias of the layers by the naming convention ''LayerXi"" where i is the index of the layer and get the status of USEMINSPACING for pins in LEF. return the results as a dict with each requirement as key names." +"def get_mterms_and_input_mterms(inst_name_1, inst_name_2): + # Get the current block of the design + block = design.getBlock() + + # Find the instances using the provided names + inst1 = block.findInst(inst_name_1) + inst2 = block.findInst(inst_name_2) + + # Get the library cells of the instances + master1 = inst1.getMaster() + master2 = inst2.getMaster() + + # Get the MTerms of the library cell of the instance inst_name_1 + mterms1 = master1.getMTerms() + + # Get the MTerms of the library cell of the instance inst_name_2 + mterms2 = master2.getMTerms() + + # List to store input MTerms of the instance inst_name_2 + input_mterms = [] + + # Iterate through each MTerm of the instance inst_name_2 + for mterm in mterms2: + # Check if the IoType is 'INPUT' + if mterm.getIoType() == 'INPUT': + # Append the MTerm to the list of input MTerms + input_mterms.append(mterm) + + # Return a tuple containing MTerms of the library cell of instance inst_name_1 and input MTerms of instance inst_name_2 + return (mterms1, input_mterms) + +# Example call to the function +results = get_mterms_and_input_mterms('_411_', 'input1')",Get the MTerms of the library cell of the instance '_411_' and get the list of mterms of the instance 'input1' whose IoType is 'INPUT'. Return the results as a tuple +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the LEF version of the technology +lef_version = tech.getLefVersion() + +# get clearance measure of the technology +clearance_measure = tech.getClearanceMeasure() + +# Set Db units per micron to 1500 for the chip +tech.setDbUnitsPerMicron(1500) + +# Return the clearance measure and the LEF version of the technology +result = (clearance_measure, lef_version)",Get the clearance measure and set the Db units per micron to 1500 to the chip and get Lef version. return the result as a tuple. +"def check_input_pins_without_nets(): + # Get the design block + block = ord.get_db_block() + + # Get all instances + insts = block.getInsts() + + # Initialize a list to store input pins without nets + input_pin_wout_net = [] + + # Iterate over instances + for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + + # Iterate over pins + for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets is None: + # Append the pin to the list + input_pin_wout_net.append(pin) + + # Check if there are no input pins without nets + return len(input_pin_wout_net) == 0 + +# Call the function and print the result +result = check_input_pins_without_nets()",Check if all the input pins of all instances have a valid net connection +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_split30_"" +inst = block.findInst(""_split30_"") +# Set the instance as don't touch type +inst.setDoNotTouch(True)","Set the instance ""_split30_"" as don't touch type" +"# Get the design block +block = ord.get_db_block() +# Get all instances +insts = block.getInsts() +# Create a list to store pin names +pin_name_list = [] +# Loop through all instances +for inst in insts: + # Get the pins of this instance + inst_ITerms = inst.getITerms() + # Loop through all pins + for ITerm in inst_ITerms: + # Append pin names to the list + pin_name_list.append(design.getITermName(ITerm))",Get the name of every pin +"# Invert the rotation and the location of instances with the library cell type 'NAND2_X1'. + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the name of the library cell type is 'NAND2_X1' + if inst.getMaster().getName() == 'NAND2_X1': + # Invert the rotation and the location of the instance + transform = inst.getTransform() + transform.invert() + inst.setTransform(transform)",Invert the rotation and the location of instances with the library cell type 'NAND2_X1' +"# Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Horizontally flip the rotation of the instance + orient = inst.getOrient() + orient = flipX(orient) + inst.setOrient(orient)",Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Horizontally flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipX(orient) + transform.setOrient(orient) + inst.setTransform(transform)",Horizontally flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' + +#define flipping function +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + +# Get the design block +block = design.getBlock() + +# Get all instances in the block +insts = block.getInsts() + +# Iterate through all instances in the block +for inst in insts: + # Check if the library cell type is 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Vertically flip the rotation of the instance + transform = inst.getTransform() + orient = transform.getOrient() + orient = flipY(orient) + transform.setOrient(orient) + inst.setTransform(transform) +",Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name 'metal8' +layer = tech.findLayer('metal8') +# Get the cut layer spacing rules +techLayerCutSpacingRules = layer.getTechLayerCutSpacingRules()",Get the cut layer spacing rules of layer with name 'metal8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal10"" +layer = tech.findLayer('metal10') +# Return the end of line extension rules +techLayerEolExtensionRules = layer.getTechLayerEolExtensionRules()",Get the end of line extension rules of the technology layer with name 'metal10' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology object with technology information +tech = block.getTech() +# Find the layer with name ""via8"" +layer = tech.findLayer('via8') +# Return the tech layer forbidden spacing rules +techLayerForbiddenSpacingRules = layer.getTechLayerForbiddenSpacingRules()",Get the forbidden spacing rules of the technology layer with name 'via8' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""via1"" +layer = tech.findLayer('via1') +# Return the keepout zone rules +techLayerKeepOutZoneRules = layer.getTechLayerKeepOutZoneRules()",Get the keepout zone rules of the technology layer with name 'via1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer called ""OVERLAP"" +layer = tech.findLayer('OVERLAP') +# Return two widths spacing rules +# API for version 5.7 two widths spacing rules, expressed as a 2D matrix +# with index tables +twoWidthsSpacingTableNumWidths = layer.getTwoWidthsSpacingTableNumWidths()",Get the two widths spacing rules of the technology layer with name 'OVERLAP' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name ""metal1"" +layer = tech.findLayer('metal1') +# Return the min cut rules +techLayerMinCutRules = layer.getTechLayerMinCutRules()",Get the minimum cut rules of the technology layer with name 'metal1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the technology layer with name ""via2"" +layer = tech.findLayer('via2') +# Return the minimum step rules +techLayerMinStepRules = layer.getTechLayerMinStepRules()",Get the minimum step rules of the technology layer with name 'via2' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the collection of spacing rules for the object, assuming +# coding in LEF 5.4 format. +v54SpacingRules = layer.getV54SpacingRules()",Get the collection of spacing rules for the layer with name 'metal3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal4"" +layer = tech.findLayer('metal4') +# Return the spacing end of line rules +techLayerSpacingEolRules = layer.getTechLayerSpacingEolRules()",Get the spacing end of line rules of layer with name 'metal4' +"def get_layer_type(layer_name): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Find the layer with the specified name + layer = tech.findLayer(layer_name) + + # Return the layer type + return layer.getType() + +# Call the function with the argument ""metal5"" +metal5_layer_type = get_layer_type('metal5')",Get the type of technology layer with name 'metal5' +"def get_via3_wrong_dir_spacing_rules(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Find the layer with name ""via3"" + layer = tech.findLayer('via3') + + # Return the wrong direction spacing rules + return layer.getTechLayerWrongDirSpacingRules() + +# Call the function to get the wrong direction spacing rules for ""via3"" +via3_wrong_dir_spacing_rules = get_via3_wrong_dir_spacing_rules()",Get the wrong direction spacing rules of layer with name 'via3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal1"" +layer = tech.findLayer('metal1') +# Return the x-axis offset +offset = layer.getOffset()",Get the offset along the x-axis of the technology layer with name 'metal1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal2"" +layer = tech.findLayer('metal2') +# Return the x-axis offset +offsetX = layer.getOffsetX()",Get the offset along the x-axis of the technology layer with name 'metal2' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the y-axis offset +offsetY = layer.getOffsetY()",Get the offset along the y-axis of the technology layer with name 'metal3' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal3"" +layer = tech.findLayer('metal3') +# Return the y-axis offset +layer.setOffsetXY(0.2, 0.15)",Change the offset setting along the x-axis to 0.2 microns and the y-axis to 0.15 microns for the technology layer named 'metal3'. +"def get_design_info(): + # Retrieve block information + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Get the technology information + tech = block.getTech() + + # Initialize a dictionary to store instance halos + inst_halos = {} + + # Iterate through each instance and store halo information + for inst in insts: + inst_halos[inst.getName()] = inst.getHalo() + + # Find layer information for 'metal4' and get EOL rules + layer4 = tech.findLayer('metal4') + layer_spacing_eol_rules = layer4.getTechLayerSpacingEolRules() + + # Find layer information for 'metal8' and get corner spacing rules + layer8 = tech.findLayer('metal8') + layer8_corner_spacing_rules = layer8.getTechLayerCornerSpacingRules() + + # Find layer information for 'metal5' and get cut class rules + layer5 = tech.findLayer('metal5') + layer_cut_class_rules = layer5.getTechLayerCutClassRules() + + # Store all the collected information in a dictionary + result = { + ""halos"": inst_halos, + ""metal4_EOL"": layer_spacing_eol_rules, + ""metal8_corner_spacing_rules"": layer8_corner_spacing_rules, + ""cut_class_rules"": layer_cut_class_rules + } + + # Return the collected information + return result + +# Call the function to get the design information +design_info = get_design_info()","Get the following in a dictionary, with the given key names: +1. get all the halos of the instances with inst name as key. the key should be halos. +2. Get the routing layers spacing EOL rules of layer with name 'metal4'. The key should be metal4_EOL. +3. Get the routing layers corner spacing rules of layer with name 'metal8'. The key should be metal8_corner_spacing_rules. +4. get the routing layers cut class rules of layer with name 'metal8'. The key name for this will be cut_class_rules." +"# Get the current design block +block = design.getBlock() + +# Retrieve the capacitor-coupled segments +cc_segments = block.getCCSegs() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store source type of instances on level 1 whose master cells are either NAND or NOR +src_type = {} + +# Iterate through each instance +for inst in insts: + # Get the library cell of the instance + master = inst.getMaster() + + # Check if the library cell is special power type + if master.isSpecialPower(): + # Set the master of the instance as frozen so dbMTerms cannot be added or delete from the master once it is frozen. + inst.getMaster().setFrozen(True) + + # Check if the name of library cell is ""NAND2_X1"" or ""NOR3_X1"" and the instance is on level 1 + if (master.getName() == ""NAND2_X1"" or master.getName() == ""NOR3_X1"") and inst.getLevel() == 1: + # Store the source type of the instance in the dictionary + src_type[inst.getName()] = inst.getSourceType()","Retrieve the capacitor-coupled segments and frozen the library cells with special power type, then get source type of all the instances on level 1 whose master cells are either ""NAND2_X1"" or ""NOR3_X1""." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Find the instance '_411_' +inst1 = block.findInst('_411_') + +# Set user-defined flags 1 and 3 for instance '_411_' +inst1.setUserFlag1() +inst1.setUserFlag3() + +# Find the instance 'input1' +inst2 = block.findInst('input1') + +# Mark the first output nets of the instances '_411_' and 'input1' +net1 = inst1.getFirstOutput().getNet() + +# Dictionary to store instance transform offsets +inst_transform_offset_dict = {} + +# Iterate through each instance +for inst in insts: + # Check if the master cell name is ""AND2X_1"" + if inst.getMaster().getName() == ""AND2X_1"": + # Store the offset of the instance with master 'AND2_X1' + inst_transform_offset_dict[inst.getName()] = inst.getTransform().getOffset()","Set user-defined flags 1 and 3 for instance '_411_' and mark the first output nets of the instances '_411_' and 'input1', followed by getting the offset of the instances whose master is 'AND2_X1' in the form of dictionary with instance name as key." +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store instances and their respective regions +inst_regions = {} + +# List to store pad instances on level 0 +inst_list = [] + +# Iterate through each instance +for inst in insts: + # Store instance name and its region in the inst_regions dictionary + inst_regions[inst.getName()] = inst.getRegion() + + # Check if the instance is a pad and it's on level 0 + if inst.isPad() and inst.getLevel() == 0: + # Append the instance to the list of pad instances + inst_list.append(inst) + + # Check if the instance name is ""input1"" + if inst.getName() == ""input1"": + # Iterate through each pin of the instance + for pin in inst.getITerms(): + # Get the net connected to the pin + net = pin.getNet() + # Check if the net exists + if net: + # Set RC disconnected for the net + net.setRCDisconnected(True)",Retrieve the instances and their corresponding areas if they are PAD or any of its subtypes and set as level 0. Proceed to disconnect the RC for the networks associated with the 'input1' instance. +"# Get the current design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Dictionary to store offsets of instances whose master cell is 'NAND2_X1' +NAND_offsets = {} + +# Iterate through each instance +for inst in insts: + # Check if the library cell name is ""NAND2_X1"" + if inst.getMaster().getName() == ""NAND2_X1"": + # Store the xy location of the instance + NAND_offsets[inst.getName()] = inst.getTransform().getOffset() + + # Check if the instance name is ""_411_"" + if inst.getName() == ""_411_"": + # Iterate through each pin of the instance + for pin in inst.getITerms(): + # Get the net connected to the pin + net = pin.getNet() + # Check if the net exists + if net: + # Set RC disconnected for the net + net.setRCDisconnected(True) +",Get the offset of all 'NAND2_X1' cells and set the RC disconnected for the nets of the instance 'input1'. +"# Get the current block of the design +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get the count of Manufacturing Grid +mfg = tech.getManufacturingGrid() + +# Find the net with name ""req_msg[13]"" +net = block.findNet(""req_msg[13]"") + +# Set the Capacitance Coupling Adjust Order of the net to 1 +net.setCcAdjustOrder(1)","Get the count of manufacturing grid and set the capacitance Coupling Adjust Order of the net with name ""req_msg[13]"" to 1." +"# Get the nets of the input pins of instance 'output53' + +block = design.getBlock() + +# find the instance 'output53' +inst = block.findInst('output53') + +# Initialize a list to store nets of input pins +input_nets = [] + +# Get all input pins (ITerms) of the instance +pins = inst.getITerms() + +# Iterate through all input pins +for pin in pins: + # Check if the pin is an input signal + if pin.isInputSignal() and pin: + # If it's an input signal, add its net to the list + input_nets.append(pin.getNet())",get the nets connected to the input pins of the instance 'output53' +"# Retrieve all instances that have a hierarchy and whose library cell type is 'AND2_X1' and are on level 1. + +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store matching instances +inst_list = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance has hierarchy, its library cell is 'AND2_X1', and it is on level 1 + if inst.isHierarchical() and inst.getMaster().getName()==""AND2_X1"" and inst.getLevel() == 1: + # Add the instance to the list + inst_list.append(inst)",Retrieve all instances that have a hierarchy and whose library cell type is 'AND2_X1' and are on level 1. +"# Get the resistor segments + +# Get the design block +block = design.getBlock() + +# Return the resistor segments +RSegs = block.getRSegs()",get the resistor segments of the design block +"# Retrieve the LEQ (Logical equivalent) information associated with the library cell of instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Get the library cell associated with the instance +master = inst.getMaster() + +# Retrieve the LEQ information +leq_info = master.getLEQ()",Retrieves the LEQ (Logical equivalent) information associated with the library cell of instance '_411_' +"# Get all the pad and set as level 1 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Initialize a list to store matching instances +inst_list = [] + +# Iterate through all instances +for inst in insts: + # Check if the instance is a pad and it is level 1 + if inst.isPad() and inst.getLevel() == 1: + # Add the instance to the list + inst_list.append(inst)",get all the pad instances that are level 1 +"# Get the vertical thickness multiplier for the IO pin placer's parameters and set corner avoidance to 50 + +# Get the IO pin placer +iop = design.getIOPlacer() + +# Get the parameters of the IO pin placer +parameters = iop.getParameters() + +# Set corner avoidance to 50 +parameters.setCornerAvoidance(50) + +# Return the vertical thickness multiplier +verticalThicknessMultiplier = parameters.getVerticalThicknessMultiplier()",get the vertical thickness multiplier for the IO pin placer's parameters and set corner avoidance to 50 +"# Get the design block +block = design.getBlock() + +# Find the instance named ""FILLER_0_17_159"" +inst = block.findInst(""FILLER_0_17_159"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Reverse the resistor segment sequence of the net + net.reverseRSegs() +",Reverse the resistor segment seqence of the nets of the instance FILLER_0_17_159 +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets with wire-ordered flag set as True +ordered_wires = [] + +# Iterate through each net +for net in nets: + # Check if the wire-ordered flag is set to true + if net.isWireOrdered(): + # Append the net to the list + ordered_wires.append(net)","Get the nets if their wire-ordered flag is set as True, and return it as a list" +"# Get the design block +block = design.getBlock() + +# List to store nets with ordered wires +ordered_wires = [] + +# List of net names +nets = [ + ""net1"", + ""net10"", + ""net11"", + ""net12"", + ""net13"", + ""net14"", + ""net15"", + ""net16"", + ""net17"", + ""net18"", + ""net19"" +] + +# Iterate through each net name +for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire ordered flag to true + net.setWireOrdered(True) + + # Append the net to the list of nets with ordered wires + ordered_wires.append(net)","Set the wires ordered flag to true for the following nets and return a list of these nets: net1, net10, net11, net12, net13, net14, net15, net16, net17, net18, net19 +" +"# Get the design block +block = design.getBlock() + +# List to store nets +altered_wires_net = [] + +# List of net names +nets = [ + ""_000_"", + ""_001_"", + ""_002_"", + ""_003_"", + ""_004_"", + ""_005_"", + ""_006_"", + ""_007_"", + ""_008_"", + ""_009_"", + ""_010_"" +] + +# Iterate through each net name +for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire update flag to true + net.setWireAltered(True) + + # Append the net to the list of nets + altered_wires_net.append(net)","Set the wire update flag to true for the wires of the following nets and return a list of these nets: _000_, _001_, _002_, _003_, _004_, _005_, _006_, _007_, _008_, _009_, _010_ +" +"# Get the design block +block = design.getBlock() + +# List to store selected nets +selected_nets = [] + +# List of net names to select +net_names = [ + ""net1"", + ""net10"", + ""net11"", + ""net12"", + ""net13"", + ""net14"", + ""net15"", + ""net16"", + ""net17"", + ""net18"", + ""net19"" +] + +# Iterate through each net name +for name in net_names: + # Find the net object by name + net = block.findNet(name) + + # Set the net as selected + net.setSelect(True) + + # Append the selected net to the list + selected_nets.append(net)","set the select flag true for the following nets and return the list of these nets: net1, net10, net11, net12, net13, net14, net15, net16, net17, net18, net19 +" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets +wild_connected_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is connected using a wild-card + if net.isWildConnected(): + # Append the net to the list + wild_connected_nets.append(net)",Get the nets connected using a wild-card. +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets marked as ""do not touch"" +do_not_touch_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is set as ""do not touch"" + if net.isDoNotTouch(): + # Append the net to the list + do_not_touch_nets.append(net)",Get the nets that are set as do not touch and return as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective coupled capacitor adjust orders +net_Cc_adjust_order = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its coupled capacitor adjust order in the dictionary + net_Cc_adjust_order[net.getName()] = net.getCcAdjustOrder()",Get the coupled capacitor adjust order for the nets of the instance input6 and return the result as a dict with key being net name and value being the coupled capacitor adjust order +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective wire types +net_wire_type = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its wire type in the dictionary + net_wire_type[net.getName()] = net.getWireType()",Get the wire types of the nets connecting to the instance input6 and return the result as a dictionary with key being net name and value being the wire type +"# Get the design block +block = design.getBlock() + +# List to store marked nets +marked_nets = [] + +# List of net names to mark +nets_to_mark = [ + ""resp_msg[4]"", + ""resp_msg[5]"", + ""resp_msg[6]"", + ""resp_msg[7]"", + ""resp_msg[8]"", + ""resp_msg[9]"", + ""resp_rdy"", + ""resp_val"" +] + +# Iterate through each net name +for name in nets_to_mark: + # Find the net object by name + net = block.findNet(name) + + # Set the mark flag of the net to True + net.setMark(True) + + # Append the marked net to the list + marked_nets.append(net)","Set mark flags to the nets resp_msg[4], resp_msg[5], resp_msg[6], resp_msg[7], resp_msg[8], resp_msg[9], resp_rdy, resp_val and return the list of market nets." +"# Get thedesign block +block = design.getBlock() + +# Find the instance named ""input6"" +inst = block.findInst(""input6"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective total resistances +net_total_resistance = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its total resistance in mil ohms in the dictionary + net_total_resistance[net.getName()] = net.getTotalResistance()","Get the total resistance in mil ohms of the nets connecting to the instance ""input6"" and return the result as a dict using net name as key and resistance as value" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets connected by abutment +abutment_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net have its pins connected by abutment + if net.isConnectedByAbutment(): + # Append the net to the list + abutment_nets.append(net)",Get the nets that have their pins connected by abutment and return as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_699_"" +inst = block.findInst(""_699_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective coupled capacitor match ratio +net_cc_match_ratio = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its coupled capacitor match ratio in the dictionary + net_cc_match_ratio[net.getName()] = net.getCcMatchRatio()","Get the coupled capacitor match ratio of the nets connecting to the instance ""_699_"" and return as a dict using net name as key and coupled capacitor match ratio as value" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input10"" +inst = block.findInst(""input10"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective node capacitors +net_cap_nodes = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its cap nodes in the dictionary + net_cap_nodes[net.getName()] = net.getCapNodes()","Get the node capacitor of the RC segment belong to each net connecting to the instance input10, and return the result as a dict with net name being keys and node capacitors as values" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name ""metal4"" +layer = tech.findLayer('metal4') +# Return the pitch of the layer +pitch = layer.getPitch()","Get the pitch setting of ""metal 4"" layer" +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store extracted nets +extracted_nets = [] + +# Iterate through each net +for net in nets: + # Check if the net is extracted + if net.isExtracted(): + # Append the extracted net to the list + extracted_nets.append(net)",Get all extracted nets as a list +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input10"" +inst = block.findInst(""input10"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective routing guides +net_guides = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its routing guides in the dictionary + net_guides[net.getName()] = net.getGuides()","Get the routing guides of the nets connecting to the instance ""input10"" as a dictionary, using net name as keys and routing guide as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""FILLER_0_17_13"" +inst = block.findInst(""FILLER_0_17_13"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective tracks +net_tracks = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its tracks in the dictionary + net_tracks[net.getName()] = net.getTracks()","Get the tracks of the nets connecting to the instance ""FILLER_0_17_13"", and return it as a dict using net name as keys and tracks as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer29"" +inst = block.findInst(""rebuffer29"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Reverse the coupled capacitor segments of the net + net.reverseCCSegs()",Reverse the coupled capacitor segments of the nets connecting to the instance called rebuffer29 +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer9"" +inst = block.findInst(""rebuffer9"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective driving ITerms +net_driving_iterm = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its driving term id assigned of this net. -1 if not set, 0 if non existent + net_driving_iterm[net.getName()] = net.getDrivingITerm()","Get the driving term ids for the nets connecting to the instance rebuffer9, and return the rsult as a dict using net name as keys and driving term ids as values" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_706_"" +inst = block.findInst(""_706_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective Cap node counts +net_cap_node_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its node capacitor count in the dictionary + net_cap_node_count[net.getName()] = net.getCapNodeCount()","Get the node capacitor count of RC segments of the nets connecting to the instance _706_, and return the result as a dictionary with keys being net name, and values being node capacitor count " +"# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets() + +# List to store nets that are RC graphs +rc_graph_nets = [] + +# Iterate through each net +for net in nets: + # Check if the rc_graph flag set, and the flag is set when Rseg and CapNodes were created + if net.isRCgraph(): + # Append the net to the list + rc_graph_nets.append(net)","Get all the nets if their rc_graph flag is set, and return the result as a list" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""split30"" +inst = block.findInst(""split30"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective term counts +net_term_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and the amount of pins and ports of this net in the dictionary + net_term_count[net.getName()] = net.getTermCount()","Get the amount of pins and ports of the nets connecting to the instance ""split30"" and return it as a dictionary with net name being keys" +"# Get the design block +block = design.getBlock() + +# Find the instance named ""clkbuf_0_clknet_2_3__leaf_clk"" +inst = block.findInst(""clkbuf_0_clknet_2_3__leaf_clk"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective x-talk classes +net_X_Talk_class = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its x-talk class in the dictionary + net_X_Talk_class[net.getName()] = net.getXTalkClass()","Get the x-talk-class of the nets connecting to the instance ""clkbuf_0_clknet_2_3__leaf_clk"", as a dictionary with the net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""rebuffer5"" +inst = block.findInst(""rebuffer5"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective first BTerms +net_first_bterms = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its first BTerm in the dictionary + net_first_bterms[net.getName()] = net.get1stBTerm()","Get the first port of the nets connecting to the instance rebuffer5, as a dictionary with the net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""input22"" +inst = block.findInst(""input22"") + +# Get all pins (interface terms) connecting to the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective R segment counts +net_R_seg_count = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its R segment count in the dictionary + net_R_seg_count[net.getName()] = net.getRSegCount()","Get the R segment count of the RC network connected to the nets of the instance input22, return the result as a dictionary with net names as key values." +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_686_"" +inst = block.findInst(""_686_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective nondefault rule applied for wiring +net_non_default_rule = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and the nondefault rule applied to this net for wiring in the dictionary, returns nullptr if there is no nondefault rule. + net_non_default_rule[net.getName()] = net.getNonDefaultRule()",Get the nondefault rule applied to the nets connected to the instance _686_ as a dictionary with the net names as key values. +"# Get the design block +block = design.getBlock() + +# Find the instance named ""_706_"" +inst = block.findInst(""_706_"") + +# Get all pins (interface terms) of the instance +pins = inst.getITerms() + +# Dictionary to store net names and their respective zeroth R segments +net_zero_R_segment = {} + +# Iterate through each pin of the instance +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + + # Check if a net is connected to the pin + if net: + # Store the net name and its zeroth R segment in the dictionary + net_zero_R_segment[net.getName()] = net.getZeroRSeg()",Get the zeroth R segment of the nets of the instance _706_ as a dictionary with the net names as key values. +"# Get the current design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Get all layers defined in the technology +layers = tech.getLayers() + +# Dictionary to store layer directions with their names +layer_direction_dict = {} + +# Dictionary to store upper and lower layers of the 'poly' layer +poly_upper_lower_layers = {} + +# Iterate through each layer +for layer in layers: + # Store the direction of the layer with its name in the dictionary + layer_direction_dict[layer.getName()] = layer.getDirection() + + # If the layer name is 'poly', store its upper and lower layers + if layer.getName() == ""poly"": + poly_upper_lower_layers = { + ""upper"": layer.getUpperLayer(), + ""lower"": layer.getLowerLayer() + } + +# Create a result dictionary containing layer directions and 'poly' upper and lower layers +result = { + ""layer_directions"": layer_direction_dict, + ""poly"": poly_upper_lower_layers +}","Get the routing directions of the layers with their names as keys and also get the layers above and below the layer with name 'poly'. Finally, return them as dict of dicts" +"def get_io_placer_report(): + # Get the IO Placer object of the design + iop = design.getIOPlacer() + + # Get the parameters of the IO Placer + parameters = iop.getParameters() + + # Construct the output string with corner avoidance, HPWL report, and number of slots + output_string = ""Corner Avoidance: {}\nHPWL Report: {}\nNumber of slots: {}"".format( + parameters.getCornerAvoidance(), + parameters.getReportHPWL(), + parameters.getNumSlots() + ) + + return output_string + +# Call the function to get the IO Placer report +io_placer_report = get_io_placer_report()","Get the corner avoidance, number of slots and HPWL report of the IO pin placer" +"def get_io_placer_lengths(): + # Get the IO Placer object of the design + iop = design.getIOPlacer() + + # Get the parameters of the IO Placer + parameters = iop.getParameters() + + # Return the vertical and horizontal length as a tuple + return (parameters.getVerticalLength(), parameters.getHorizontalLength()) + +# Call the function to get the lengths +io_placer_lengths = get_io_placer_lengths()",Get the vertical and horizontal length of the setting of the IO pin placer +"from openroad import Tech, Design + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 10 um +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()","Show me the piece of code to perform floorplanning using a utilization rate of 50% and an aspect ratio of 0.66, and set the spacing between the core and the die to 10 microns" +"def get_master_types_of_instances(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Retrieve all instances present in the design block + insts = block.getInsts() + + # Initialize an empty list to store the names of library cell type for each instance + masters_list = [] + + # Iterate over each instance in the design block + for inst in insts: + # Retrieve the library cell type of the current instance + master_type = inst.getMaster() + # Get the name of the library cell type + master_type_name = master_type.getName() + # Append the name of the library cell type to the list + masters_list.append(master_type_name) + + return masters_list + +# Call the function to get the master types +master_types_list = get_master_types_of_instances()",Give me the names of library cell type of every instance +"def get_instance_levels(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Retrieve all instances present in the design block + insts = block.getInsts() + + # Dictionary to store the level of each instance + level_of_instance = {} + + # Iterate over each instance in the design block + for inst in insts: + # Retrieve the name of the instance and its level, then store it in the dictionary + level_of_instance[inst.getName()] = inst.getLevel() + + return level_of_instance + +# Call the function to get the instance levels +instance_levels = get_instance_levels()",Get the level of all instances with the instance name as a dictionary. Key of the dictionary is name of the instance and value is the level of the instance +"def get_const_names_of_instances(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Retrieve all instances present in the design block + insts = block.getInsts() + + # Initialize an empty list to store the constant names of the instances + const_name = [] + + # Iterate over each instance in the design block + for inst in insts: + # Append the constant name of the instance + const_name.append(inst.getConstName()) + + return const_name + +# Call the function to get the constant names +constant_names = get_const_names_of_instances()",Get all the Constant names of the instances and return as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +print("" name | net_type | pin&wire_capacitance"") +# Retrieve all nets present in the design block +nets = block.getNets() +# Iterate over each net in the design block +for net in nets: + # Get the net capacitance + pin_and_wire_cap = timing.getNetCap(net, corner, timing.Max) + # Get the name of the net + net_name = net.getName() + # Get the signal Type of the net + net_type = net.getSigType() + print(f""{net_name:<12}| {net_type:<9}| {pin_and_wire_cap:19.4e}"")","Write a code to Print the name of the net, its net type, and the wire capacitance of all the nets" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Retrieve all instances present in the design block +insts = block.getInsts() +print("" name | rise_arrival_time | fall_arrival_time | rise_slack | fall_slack | slew"") +# Iterate over each instance in the design block +for inst in insts: + # Get the pins associated with the instance + inst_ITerms = inst.getITerms() + # Iterate through all the pins + for pin in inst_ITerms: + # Check if the pin is in supply + if design.isInSupply(pin): + continue + # Get the pin name + pin_name = design.getITermName(pin) + # Get the pin rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Get the pin fall arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Get the pin rise slack + pin_rise_slack = timing.getPinSlack(pin, timing.Fall, timing.Max) + # Get the pin fall slack + pin_fall_slack = timing.getPinSlack(pin, timing.Rise, timing.Max) + # Get the pin slew + pin_slew = timing.getPinSlew(pin) + print(f""{pin_name:<12} | {pin_rise_arr:17.4e} | {pin_fall_arr:17.4e} | {pin_rise_slack:10.4e} | {pin_fall_slack:10.4e} | {pin_slew:6.4e}"") ","Write a code to print all the pin names, rising arrival time, fall arrival time, rise stack, fall stack and slew of all the pins" +"def get_number_of_library_cell_types(): + # Get the OpenROAD database + db = ord.get_db() + + # Get the number of library cell types + return db.getNumberOfMasters() + +# Call the function to get the number of library cell types +num_library_cell_types = get_number_of_library_cell_types()",Get the number of library cells in the library +"def calculate_die_area(): + # Get the design block + block = ord.get_db_block() + + # Get the die area of the design + area = block.getDieArea() + + # Get the width and height of the die area + dx = area.dx() + dy = area.dy() + + # Calculate the die area + die_area = dx * dy + + return die_area + +# Call the function to calculate the die area +die_area = calculate_die_area()",Get the die area +"def calculate_core_area(): + # Get the design block + block = ord.get_db_block() + + # Get the core area of the design + area = block.getCoreArea() + + # Get the width and height of the core area + dx = area.dx() + dy = area.dy() + + # Calculate the core area + core_area = dx * dy + + return core_area + +# Call the function to calculate the core area +core_area = calculate_core_area()",Get the core area +"def report_global_connections(): + # Get the design block + block = ord.get_db_block() + + # Report global connection of the design + global_connection = block.reportGlobalConnect() + + return global_connection + +# Call the function to report global connections +global_connections = report_global_connections()",Report all the global connection rules +"def calculate_total_pins(): + # Get the design block + block = ord.get_db_block() + + # Initialize a variable to store the total number of pins + total_pins = 0 + + # Get instances + insts = block.getInsts() + + # Iterate over instances + for inst in insts: + # Add the number of pins of the instance to the total + total_pins += len(inst.getITerms()) + + return total_pins + +# Call the function to calculate the total number of pins +total_pins = calculate_total_pins()",Get the total number of pins +"def check_clock_nets_exist(): + # Get the design block + block = ord.get_db_block() + + # Initialize a list to store clock nets + clock_nets = [] + + # Get all nets + nets = block.getNets() + + # Iterate over nets + for net in nets: + # Check if the net is a CLOCK net + if net.getSigType() == 'CLOCK': + clock_nets.append(net) + + # Check if CLOCK nets exist + return len(clock_nets) > 0 + +# Call the function to check for the existence of clock nets +clock_nets_exist = check_clock_nets_exist()",Check if the design has any clock nets +"def count_power_and_ground_nets(): + # Get the design block + block = ord.get_db_block() + + # Initialize variables to count power and ground nets + power_nets = 0 + ground_nets = 0 + + # Get all nets + nets = block.getNets() + + # Iterate over nets + for net in nets: + # Check if the net is a POWER net + if net.getSigType() == 'POWER': + power_nets += 1 + # Check if the net is a GROUND net + elif net.getSigType() == 'GROUND': + ground_nets += 1 + + # Return the counts of power and ground nets + return power_nets, ground_nets + +# Call the function to get the counts of power and ground nets +power_net_count, ground_net_count = count_power_and_ground_nets()",Get the total number of power and ground nets +"# Get the chip associated with the design's block. + +# Retrieve the design block +block = design.getBlock() + +# Get the chip associated with the design block. +chip = block.getChip() ",Give me the chip of a given block +"# Get the nets in a given block + +# Get the design block +block = design.getBlock() + +# Get all nets +nets = block.getNets()",Get all nets in a given block +design.getBlock().getName(),Get the name of the design block +"# Get the logic ports for a given block + +# Get the design block +block = design.getBlock() + +# Get all logic ports +logic_ports = block.getLogicPorts()",Get the logic ports for a given block +"# Get the location of all instances +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through all instances +for inst in insts: + # Print the instance name and its location + print(inst.getName(), ""Location:"", inst.getLocation())",Get the location of all instances +"def is_instance_placed(instance_name): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Iterate through all instances + for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == instance_name: + # Return the placement status of the instance + return inst.isPlaced() + + # Return None if the instance is not found + return None + +# Call the function to check if 'FILLER_0_0_1' is placed +is_filler_placed = is_instance_placed('FILLER_0_0_1')",Check if the instance 'FILLER_0_0_1' placed or not +"def get_instance_children(instance_name): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Iterate through all instances + for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == instance_name: + # Get the children instances of the target instance + return inst.getChildren() + + # Return an empty list if the instance is not found or has no children + return [] + +# Call the function to get the children of 'FILLER_0_0_1' +filler_children = get_instance_children('FILLER_0_0_1')",Get the children of 'FILLER_0_0_1' instance +"def get_net_with_max_capacitance(block, timing, corner): + # Get all nets + nets = block.getNets() + # Initialize variables to track the net with the maximum capacitance + max_cap_net = None + max_cap = float('-inf') + # Iterate over nets + for net in nets: + # Get the total capacitance of the net + cap = timing.getNetCap(net, corner, timing.Max) + # Check if the capacitance of the current net is greater than the maximum capacitance found so far + if cap > max_cap: + # Update the maximum capacitance and the corresponding net + max_cap = cap + max_cap_net = net + # Return the name of the net with the maximum capacitance + return max_cap_net.getName() if max_cap_net else None + +# Example usage: +# Assuming `ord`, `timing`, and `corner` are initialized appropriately. +block = ord.get_db_block() +net_with_max_cap = get_net_with_max_capacitance(block, timing, corner)",Identify the nets with the highest capacitance +"def get_high_fanout_nets(): + # Get the design block + block = ord.get_db_block() + # Get all nets + nets = block.getNets() + # Define the fanout threshold + gt_fanout = 10 + # Initialize a list to store nets with fanout greater than the threshold + net_fanout = [] + # Iterate over nets + for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if net_ITerm.isInputSignal(): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Check if the number of output pins exceeds the fanout threshold + if len(output_pins) > gt_fanout: + # Append the net name and its fanout to the list + net_fanout.append([net_name, len(output_pins)]) + # Return the list of nets with fanout greater than the threshold + return net_fanout + +# Call the function +high_fanout_nets = get_high_fanout_nets()",Give me a list of nets with a fanout greater than 10 +"# Get the design block +block = ord.get_db_block() +# Get all nets +nets = block.getNets() +# Initialize variables to store maximum fanout and its corresponding net +max_fanout = 0 +# Lists to store net names and their corresponding fanouts +net_fanout_list = [] +net_name_list = [] +# Iterate over nets +for net in nets: + # Get the name of the net + net_name = net.getName() + # Initialize a list to store output pins + output_pins = [] + # Get all ITerms associated with the net + net_ITerms = net.getITerms() + # Iterate over ITerms + for net_ITerm in net_ITerms: + # Check if the ITerm represents an input signal + if (net_ITerm.isInputSignal()): + # Get the name of the pin + pin_name = design.getITermName(net_ITerm) + # Append the pin name to the list of output pins + output_pins.append(pin_name) + # Append the net name and its fanout to the respective lists + net_name_list.append(net_name) + net_fanout_list.append(len(output_pins)) +# Find the maximum fanout +max_fanout = max(net_fanout_list) +# Find the index of the net with the maximum fanout +max_fanout_index = net_fanout_list.index(max_fanout) +# Get the name of the net with the maximum fanout +max_fanout_net = net_name_list[max_fanout_index] +# Return the net with the maximum fanout +return max_fanout_net",Give me a list of nets with the maximum fanout +"def get_unique_master_cell_names(): + # Get the design block + block = ord.get_db_block() + # Get all instances + insts = block.getInsts() + # Initialize a list to store unique name of library cell types + masters_list = [] + # Iterate over instances + for inst in insts: + # Get the master associated with the instance + mast = inst.getMaster() + mast_name = mast.getName() + # Check if the library cell name is not already in the list + if mast_name not in masters_list: + # Append the library cell name to the list + masters_list.append(mast_name) + # Return the list of unique library cell names + return masters_list + +# Call the function +unique_masters = get_unique_master_cell_names()",List all the library cells used +"# Get the design block +block = ord.get_db_block() +# Get the total number of connections (nets) +total_connections = len(block.getNets())",Get the total number of connections (nets) +"def get_io_nets(): + # Get the design block + block = design.getBlock() + + # Get all nets + nets = block.getNets() + + # Initialize a list to store input/output nets + io_nets = [] + + # Iterate through all nets + for net in nets: + # Check if the net is an input/output net + if net.isIO(): + # If it's an input/output net, add it to the list + io_nets.append(net) + + # Return the list of input/output nets + return io_nets + +# Call the function +io_nets = get_io_nets()",get all the input output nets for a given block +"def get_output_pins(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a list to store output pins + output_pins_list = [] + + # Iterate through all instances + for inst in insts: + # Get all input pins (ITerms) of the instance + pins = inst.getITerms() + # Iterate through all input pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # If it's an output signal, add it to the list + output_pins_list.append(pin) + + # Return the list of output pins + return output_pins_list + +# Call the function +output_pins = get_output_pins()",get a list of all the output pins +"def get_nets_for_instance(inst_name): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a variable to store the nets of the instance + nets = None + + # Iterate through all instances + for inst in insts: + # Check if the instance name matches the target instance + if inst.getName() == inst_name: + # Get all pins (ITerms) of the instance and extract their associated nets + nets = [pin.getNet() for pin in inst.getITerms()] + break + + # Return the nets of the instance + return nets + +# Call the function with the instance name '_411_' +instance_nets = get_nets_for_instance('_411_')",Give me all nets connecting to the instance '_411_' +"def get_instance_weights(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store weights of instances + inst_weight_dict = {} + + # Iterate through all instances + for inst in insts: + # Get the instance name + name = inst.getName() + # Check if the instance name is not already in the dictionary + if name not in inst_weight_dict: + # If not, add the instance name and its weight to the dictionary + inst_weight_dict[name] = inst.getWeight() + + # Return the dictionary containing weights of instances + return inst_weight_dict + +# Call the function to get the instance weights +instance_weights = get_instance_weights()",get Weights of all the instances +"def get_instance_bbox_dimensions(inst_name='_411_'): + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(inst_name) + + # Get the length and width of the Bounding Box of the instance + length = inst.getBBox().getLength() + width = inst.getBBox().getWidth() + + # Return the length and width + return (length, width) + +# Call the function to get the length and width of the instance '_411_' +bbox_dimensions = get_instance_bbox_dimensions('_411_')",get length and width of the bounding Box of the instance ''_411_' +"def get_source_types_of_instances_at_level(level=1): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store source types of instances at the specified level + inst_src_type_dict = {} + + # Iterate through all instances + for inst in insts: + # Check if the instance is at the specified level + if inst.getLevel() == level: + # Add the instance name and its source type to the dictionary + inst_src_type_dict[inst.getName()] = inst.getSourceType() + + # Return the dictionary containing source types of instances at the specified level + return inst_src_type_dict + +# Call the function to get source types of instances on level 1 +lvl1_inst_src_type = get_source_types_of_instances_at_level(1)",get source type of all the instance on level 1 +"# Set the placement status of the instance '_411_' to 'UNPLACED' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the placement status of the instance to 'UNPLACED' +inst.setPlacementStatus('UNPLACED') +",set the placement Status of the instance '_411_' to 'UNPLACED' +"# Get all the blockages + +# Get the design block +block = design.getBlock() + +# Return all blockages +blockages = block.getBlockages()",get all the blockages +"# Reset the tapcell in the design + +# Get the tapcell in the design +tapcell = design.getTapcell() + +# Reset the tapcell +tapcell.reset()",reset the tapcell in the design +"# Retrieve the capacitor-coupled segments + +# Get the design block +block = design.getBlock() + +# Return the capacitor-coupled segments +CCSegs = block.getCCSegs()",retrieve the capacitor-coupled segments +"def get_sites_of_rows(): + # Get the design block + block = design.getBlock() + + # Get all rows + rows = block.getRows() + + # Initialize a dictionary to store row names and their corresponding sites + row_site_dict = {} + + # Iterate through all rows + for row in rows: + # Add the row name and its site to the dictionary + row_site_dict[row.getName()] = row.getSite() + + # Return the dictionary containing row names and their sites + return row_site_dict + +# Call the function to get the sites of rows +row_sites = get_sites_of_rows()",get the sites of rows +"def get_row_site_dimensions(): + # Get the design block + block = design.getBlock() + + # Get all rows + rows = block.getRows() + + # Initialize a dictionary to store row names and their corresponding site dimensions + row_site_dict = {} + + # Iterate through all rows + for row in rows: + # Check if the row has a site + if row.getSite(): + # Add the row name and its site dimensions to the dictionary + row_site_dict[row.getName()] = [row.getSite().getHeight(), row.getSite().getWidth()] + + # Return the dictionary containing row names and their site dimensions + return row_site_dict + +# Call the function to get row site dimensions +row_site_dimensions = get_row_site_dimensions()",get the height and width of the sites of each row +"# Get the location, orientation, direction, and spacing of rows + +# Get the design block +block = design.getBlock() + +# Get all rows +rows = block.getRows() + +# Iterate through all rows +for i in range(len(rows)): + row = rows[i] + # Print row information + print(""Row"", i, row.getName()) + print(""Location:"", row.getOrigin()) + print(""Rotation:"", row.getOrient()) + print(""Direction:"", row.getDirection()) + print(""Block spacing:"", row.getSpacing()) +","get the location, rotation, direction and spacing of rows" +"def get_rows_with_hybrid_sites(): + # Get the design block + block = design.getBlock() + + # Get all rows + rows = block.getRows() + + # Initialize a list to store rows with hybrid sites + hybrid_row_site = [] + + # Iterate through all rows + for i in range(len(rows)): + row = rows[i] + site = row.getSite() + # Check if the site is hybrid + if site.isHybrid(): + # Append the row and its site to the list + hybrid_row_site.append((row, site)) + + # Return the list of rows with hybrid sites + return hybrid_row_site + +# Call the function to get rows with hybrid sites +hybrid_rows = get_rows_with_hybrid_sites()",get the rows with hybrid sites +"def get_instances_and_halos(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store instances and their halos + inst_halos = {} + + # Iterate through all instances + for inst in insts: + # Add the instance name and its halo to the dictionary + inst_halos[inst.getName()] = inst.getHalo() + + # Return the dictionary containing instances and their halos + return inst_halos + +# Call the function to get instances and their halos +instances_and_halos = get_instances_and_halos()",get all the instances and there halos +"def get_instances_and_regions(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store instances and their regions + inst_regions = {} + + # Iterate through all instances + for inst in insts: + # Add the instance name and its region to the dictionary + inst_regions[inst.getName()] = inst.getRegion() + + # Return the dictionary containing instances and their regions + return inst_regions + +# Call the function to get instances and their regions +instances_and_regions = get_instances_and_regions()",get the instances and their respective regions +"def get_and_set_do_not_touch(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store do not touch instances + do_not_touch_elements = {} + + # Iterate through all instances + for inst in insts: + # Check if the instance is marked as do not touch + if inst.isDoNotTouch(): + # Add the instance to the dictionary + do_not_touch_elements[inst.getName()] = inst + else: + # Set do not touch to true for instances marked as false + inst.setDoNotTouch(True) + + # Return the dictionary containing do not touch instances + return do_not_touch_elements + +# Call the function to get and set ""do not touch"" instances +do_not_touch_instances = get_and_set_do_not_touch()",get the all the do not touch instance and set do not touch to true if false for instances +"def set_eco_create_and_destroy(inst_name): + # Get the design block + block = design.getBlock() + + # Find the instance by name + inst = block.findInst(inst_name) + + # Set EcoCreate and EcoDestroy to true + inst.setEcoCreate(True) + inst.setEcoDestroy(True) + + # Return the modified instance + return inst + +# Call the function for instance '_411_' +modified_instance = set_eco_create_and_destroy('_411_')",set the EcoCreate and EcoDestroy for instance '_411_' true +"# Mark the first output nets of the instances '_411_' and 'input1' + +# Get the design block +block = design.getBlock() + +# Find the instances '_411_' and 'input1' +inst1 = block.findInst('_411_') +inst2 = block.findInst('input1') + +# Mark the first output net of instance '_411_' +inst1.getFirstOutput().getNet().setMark(True) + +# Mark the first output net of instance 'input1' +inst2.getFirstOutput().getNet().setMark(True) +",mark the first output nets of the instances '_411_' and 'input1' +"def get_rc_disconnected_nets(): + # Get the design block + block = design.getBlock() + + # Get all the nets + nets = block.getNets() + + # Initialize a list to store RC disconnected nets + rc_disconnected_nets = [] + + # Iterate through all the nets + for net in nets: + # Check if the net is RC disconnected + if net.isRCDisconnected(): + # Add the net to the list + rc_disconnected_nets.append(net) + + # Return the list of RC disconnected nets + return rc_disconnected_nets + +# Call the function to get RC disconnected nets +disconnected_nets = get_rc_disconnected_nets()",Get the nets that are disconnected from RC network +"def get_placement_boundary_points(): + # Hard-coded parameters + block_name = '_411_' + + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(block_name) + + # Get the library cell associated with the instance + master = inst.getMaster() + + # Get the placement bounding box of the library cell + placement_boundary = master.getPlacementBoundary() + + # Return the points of the placement bounding box + return placement_boundary.getPoints() + +# Call the function and store the result +boundary_points = get_placement_boundary_points() +print(boundary_points)",get the points of the placement bounding box of the library cell of the instance '_411_' +"# Clear user flags of instance '_411_' + +# Get the design block +block = design.getBlock() + +# Find the instance with name '_411_' +inst = block.findInst('_411_') + +# Clear user flags 1, 2, and 3 of the instance +inst.clearUserFlag1() +inst.clearUserFlag2() +inst.clearUserFlag3()",clear user flags of instance '_411_' +"def check_end_cap_status(): + # Hard-coded parameter + instance_name = '_411_' + + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Check if the instance is marked as an end cap + return inst.isEndCap() + +# Call the function and store the result +is_end_cap = check_end_cap_status() +print(is_end_cap)",Check if the instance '_411_' is marked as an end cap cell. +"def map_nets_to_wires(): + # Get the design block + block = design.getBlock() + + # Get all nets + nets = block.getNets() + + # Initialize a dictionary to store net-wire mappings + net_wire_dict = {} + + # Iterate through all nets + for net in nets: + # Get the name of the net + net_name = net.getName() + + # If the net name is not already in the dictionary, initialize an empty list + if net_name not in net_wire_dict: + net_wire_dict[net_name] = [] + + # Append the wire connected to the net to the list in the dictionary + net_wire_dict[net_name].append(net.getWire()) + + # Return the net-wire dictionary + return net_wire_dict + +# Call the function and store the result +net_wire_mapping = map_nets_to_wires() +print(net_wire_mapping)",map nets to the wires +"def get_master_cell_mterms(): + # Hard-coded parameter + instance_name = '_411_' + + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Get the MTerms of the master cell + mterms = inst.getMaster().getMTerms() + + # Return the MTerms + return mterms + +# Call the function and store the result +master_cell_mterms = get_master_cell_mterms() +print(master_cell_mterms)",get the MTerms of the master cell of the instance '_411_' +"def get_iotypes_of_pins(): + # Hard-coded parameter + instance_name = '_411_' + + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Get the MTerms of the master cell + mterms = inst.getMaster().getMTerms() + + # Initialize a dictionary to store IoTypes + iotype_dict = {} + + # Iterate through all MTerms + for term in mterms: + # Store the IoType of each term in the dictionary + iotype_dict[term.getName()] = term.getIoType() + + # Return the dictionary containing IoTypes + return iotype_dict + +# Call the function and store the result +pin_iotypes = get_iotypes_of_pins() +print(pin_iotypes)",get the IoType of the pins of the instance '_411_' +"def get_non_core_instances(): + # Get the design block + block = design.getBlock() + + # Get all instances in the block + insts = block.getInsts() + + # Initialize an empty list for non-core instances + inst_list = [] + + # Iterate through all instances + for inst in insts: + # If the instance's master cell is not a core, add it to the list + if not inst.getMaster().isCore(): + inst_list.append(inst) + + # Return the list of non-core instances + return inst_list + +# Call the function and store the result +non_core_instances = get_non_core_instances() +print(non_core_instances)",get the instances whose masters are not of type CORE +"def get_num_masks_per_layer(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the number of masks for each layer + num_masks = {} + + # Iterate through all layers + for layer in layers: + # Store the number of masks for each layer + num_masks[layer.getName()] = layer.getNumMasks() + + # Return the dictionary containing the number of masks for each layer + return num_masks + +# Call the function and store the result +layer_masks = get_num_masks_per_layer() +print(layer_masks)",get the number of masks of each layer +"def get_clearance_measure(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Return the clearance measure + return tech.getClearanceMeasure() + +# Call the function and store the result +clearance_measure = get_clearance_measure() +print(clearance_measure)",get the measure system +"def check_use_min_spacing(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Return whether UseMinSpacingObs is set in the technology + return tech.getUseMinSpacingObs() + +# Call the function and store the result +use_min_spacing = check_use_min_spacing() +print(use_min_spacing)",Check LEF USEMINSPACING is set or not +"def get_rect_only_layers(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a list to store layers set as RectOnly + rect_layers = [] + + # Iterate through all layers + for layer in layers: + # Check if the layer is set as RectOnly + if layer.isRectOnly(): + # Append the rectangle-only layer to the list + rect_layers.append(layer) + + # Return the list of rectangle-only layers + return rect_layers + +# Call the function and store the result +rect_only_layers = get_rect_only_layers() +print(rect_only_layers)",Get the layers if they are set as isRectOnly +"def get_layer_aliases(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the Alias of each layer + layer_alias = {} + + # Iterate through all layers + for layer in layers: + # Store the Alias of each layer + layer_alias[layer.getName()] = layer.getAlias() + + # Return the dictionary containing the Alias of all layers + return layer_alias + +# Call the function and store the result +layer_aliases = get_layer_aliases() +print(layer_aliases)",Get the alias of all the layers +"def set_layer_aliases(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the Alias of each layer + layer_alias = {} + + # Iterate through all layers + for layer in layers: + # Construct the Alias using the layer index + alias = ""Layer "" + str(layer.getNumber()) + + # Set the Alias of the layer + layer.setAlias(alias) + + # Store the Alias of the layer in the dictionary + layer_alias[layer.getName()] = alias + + # Return the dictionary containing the updated Alias of layers + return layer_alias + +# Call the function and store the result +updated_layer_aliases = set_layer_aliases() +print(updated_layer_aliases)","Set the Alias of the layers by the name convention ''layer i"" where i is the index of the layer" +"# Get LEF version + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return the LEF version of the technology +LefVersion = tech.getLefVersion()",Get LEF version +"# Get LEF version as a string + +# Get the design block +block = design.getBlock() + +# Get the technology information +tech = block.getTech() + +# Return the LEF version of the technology as a string +LefVersionString = tech.getLefVersionStr()",Get LEF version as a string +"def get_layer_resistances(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the resistance of each layer + layer_resistance = {} + + # Iterate through all layers + for layer in layers: + # Get the resistance of the layer and store it in the dictionary + layer_resistance[layer.getName()] = layer.getResistance() + + # Return the dictionary containing the resistance of each layer + return layer_resistance + +# Call the function and store the result +layer_resistances = get_layer_resistances() +print(layer_resistances)",Get the resistance of all the layers +"def get_layer_edge_capacitances(): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Get all layers + layers = tech.getLayers() + + # Initialize a dictionary to store the edge capacitance of each layer + layer_edge_capacitance = {} + + # Iterate through all layers + for layer in layers: + # Get the edge capacitance of the layer and store it in the dictionary + layer_edge_capacitance[layer.getName()] = layer.getEdgeCapacitance() + + # Return the dictionary containing the edge capacitance of each layer + return layer_edge_capacitance + +# Call the function and store the result +layer_edge_capacitances = get_layer_edge_capacitances()",get edge capacitance of all the layers +"def get_upper_lower_layers(layer_name): + # Get the design block + block = design.getBlock() + + # Get the technology information + tech = block.getTech() + + # Find the layer with the specified name + layer = tech.findLayer(layer_name) + + # Return the upper and lower layer of the specified layer + return (layer.getUpperLayer(), layer.getLowerLayer()) + +# Call the function and store the result with 'metal5' as the argument +upper_lower_layers = get_upper_lower_layers('metal5')",get the upper and lower layer of the layer 'metal5' +"def check_buffer_and_end_cap(): + # Hard-coded parameter + instance_name = '_411_' + + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Get the master of the instance + master = inst.getMaster() + + # Check if the design is buffer for the master and if the master is End Cap + return design.isBuffer(master) and master.isEndCap() + +# Call the function and store the result +buffer_and_end_cap_status = check_buffer_and_end_cap()",Check if instance '_411_' is buffer and if it is an End Cap cell +"def process_sequential_instances(): + target_inst_name = ""_411_"" + + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock(block_name) # Get the block + insts = block.getInsts() # Get all instances + + seq_insts = [] # List to store sequential instances + + # Iterate through instances + for inst in insts: + master = inst.getMaster() # Get the master of the instance + + # Check if the instance is '_411_' + if inst.getName() == target_inst_name: + # Make the master of instance '_411_' sequential + master.setSequential(True) + + # Check if the master is of type sequential + if master.isSequential(): + seq_insts.append(inst) + + # Return sequential instances + return seq_insts + +# Call the function +sequential_instances = process_sequential_instances()",Get the instances whose masters are of type sequential and make the master of instance '_411_' sequential +"def check_clocked_pins(inst_name): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the instance based on the provided name + inst = block.findInst(inst_name) + + # Get all pins of the instance + pins = inst.getITerms() + + clocked_ports = [] # List to store pins set as clocked + + # Check if any pin is set as clocked + for pin in pins: + if pin.isClocked(): + clocked_ports.append(pin) + + # Return clocked ports + return clocked_ports + +# Call the function with '_411_' as an argument +clocked_pins = check_clocked_pins('_411_')",Check if the instance '411' has any pin set as clocked +"# Display the location, orient, direction, and spacing of each row +block = design.getBlock() +rows = block.getRows() + +# Print table header +print(""{:<15} {:<15} {:<15} {:<15}"".format(""Row Name"", ""Location"", ""Direction"", ""Spacing"")) + +# Print data in a table format +for row in rows: + location = str(row.getOrigin()) + direction = str(row.getDirection()) + spacing = str(row.getSpacing()) + + print(""{:<15} {:<15} {:<15} {:<15}"".format(row.getName(), location, direction, spacing))","Display the location, orient, direction, and spacing of each row" +"def get_rows_and_output_pins_by_orient(orient): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + rows = block.getRows() # Get all rows + insts = block.getInsts() # Get all instances + + output_pins_dict = {} # Dictionary to store output pins + orient_rows = [] # List to store rows with the specified orientation + + # Iterate over rows to find those with the specified rotation orientation + for row in rows: + if row.getOrient() == orient: + orient_rows.append(row) + + # Iterate over instances to find their output pins + for inst in insts: + if inst.getFirstOutput(): + output_pins_dict[inst.getName()] = inst.getFirstOutput() + + # Return the rows with the specified orientation and output pins of instances + return (orient_rows, output_pins_dict) + +# Call the function with 'MX' as the argument +orient_rows, output_pins_dict = get_rows_and_output_pins_by_orient('MX')",Get the rows with 'MX' rotation and get the instances and the first output pin of all instances. +"def get_instances_halos_and_regions(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + insts = block.getInsts() # Get all instances + + inst_halo_region_dict = {} # Dictionary to store instance names with their halos and regions + + # Iterate over instances to collect their halos and regions + for inst in insts: + inst_halo_region_dict[inst.getName()] = (inst.getHalo(), inst.getRegion()) + + # Return the dictionary with instance names as keys and a tuple of halo net and region as values + return inst_halo_region_dict + +# Call the function +inst_halo_region_dict = get_instances_halos_and_regions()",Get all the instances and their halos and regions in a dictionary with the instance name as the key and a tuple of halo net and region as value +"def set_do_not_touch_and_eco_create_destroy(inst_name): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + insts = block.getInsts() # Get all instances + + dnt_insts = [] # List to store 'Do Not Touch' instances + + # Iterate over instances to set 'Do Not Touch' for pads and collect 'Do Not Touch' instances + for inst in insts: + if inst.isPad(): + inst.setDoNotTouch(True) # Set Do Not Touch to True for pad instances + + if inst.isDoNotTouch(): + dnt_insts.append(inst) # Collect Do Not Touch instances + + # Set the EcoCreate and EcoDestroy for the specified instance to True + if inst.getName() == inst_name: + inst.setEcoCreate(True) + inst.setEcoDestroy(True) + + # Return the list of 'Do Not Touch' instances + return dnt_insts + +# Call the function with '_411_' as an argument +dnt_insts = set_do_not_touch_and_eco_create_destroy('_411_')",Get the all the do not touch instances and set do not touch to true for pad instances and set the EcoCreate and EcoDestroy for instance '_411_' to True. +"def mark_first_output_and_set_rc_disconnected(inst_name1, inst_name2): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the instances by names + inst1 = block.findInst(inst_name1) + inst2 = block.findInst(inst_name2) + + # Mark the first output nets of the instances and set RC disconnected true for the nets + inst1.getFirstOutput().getNet().setMark(True) + inst2.getFirstOutput().getNet().setMark(True) + + # Set RC disconnected true for the net of the first output of the first instance + inst1.getFirstOutput().getNet().setRCDisconnected(True) + + # Set RC disconnected true for the net of the first output of the second instance + inst2.getFirstOutput().getNet().setRCDisconnected(True) + +# Call the function with '_411_' and 'input1' as arguments +mark_first_output_and_set_rc_disconnected('_411_', 'input1')",Mark the first output nets of the instances '411' and 'input1' and set RC disconnected to True for the nets. +"def set_rc_disconnected_and_get_coordinates(inst_name): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the instance by name + inst = block.findInst(inst_name) + + # Set RC disconnected true for the nets of the instance + nets = [pin.getNet() for pin in inst.getITerms()] + for net in nets: + if net: + net.setRCDisconnected(True) + + # If the instance is '_411_', get the placement coordinates of its master cell + if inst.getName() == ""_411_"": + placement_boundary = inst.getMaster().getPlacementBoundary() + coordinates = { + ""ul"": placement_boundary.ul(), + ""ll"": placement_boundary.ll(), + ""lr"": placement_boundary.lr(), + ""ur"": placement_boundary.ur() + } + return coordinates + +# Call the function with 'input1' to set RC disconnected and get coordinates for '_411_' +coordinates = set_rc_disconnected_and_get_coordinates('input1')","Set the RC disconnected true for the nets of the instance 'input1' and get the upper-left, lower-left, lower-right, upper-right coordinates of the placement bounding box of the master cell of the instance '411'." +"def clear_user_flags_and_get_placement_points(inst_name): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the instance by name + inst = block.findInst(inst_name) + + # Get the placement bounding box of the master cell of the instance + placement_boundary = inst.getMaster().getPlacementBoundary() + + # Get the points of the placement bounding box + points = placement_boundary.getPoints() + + # Clear user flags 1, 2, and 3 of the instance + inst.clearUserFlag1() + inst.clearUserFlag2() + inst.clearUserFlag3() + + # Return the points of the placement bounding box + return points + +# Call the function with '_411_' to clear user flags and get placement points +placement_points = clear_user_flags_and_get_placement_points('_411_')",Get the points of the placement bounding box of the master cell of the instance '411' and clear user flags of instance '_411_'. +"def getMasterCellCoordinates(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get all instances + instances = block.getInsts() + + # Initialize a dictionary to store coordinates for each master cell + masterCoordinates = {} + + # Iterate through each instance + for instance in instances: + # Get the master cell of the instance + masterCell = instance.getMaster() + + # Get the placement bounding box of the master cell + placementBoundary = masterCell.getPlacementBoundary() + + # Check if the master cell name is not already in the masterCoordinates dictionary + if masterCell.getName() not in masterCoordinates: + # Store the center x, y coordinates, and minimum and maximum x, y coordinates in the dictionary + masterCoordinates[masterCell.getName()] = { + ""center"": [placementBoundary.xCenter(), placementBoundary.yCenter()], + ""min"": [placementBoundary.xMin(), placementBoundary.yMin()], + ""max"": [placementBoundary.xMax(), placementBoundary.yMax()] + } + + # Return the dictionary containing coordinates for each master cell + return masterCoordinates + +# Call the function to get the coordinates +masterCoordinates = getMasterCellCoordinates()","Get the center x, y and minimum and maximum x, y coordinates of the placement bounding box of the master cell of the all instance." +"def getLayerSpacingAndMasks(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # Dictionary to store spacing and number of masks for each layer + spacingAndMask = {} + + # Iterate through each layer in the technology + for layer in layers: + # Store the spacing and number of masks for the current layer in the dictionary + spacingAndMask[layer.getName()] = { + ""spacing"": layer.getSpacing(), + ""masks"": layer.getNumMasks() + } + + # Return the dictionary containing spacing and number of masks for each layer + return spacingAndMask + +# Call the function to get the spacing and masks for all layers +layerSpacingAndMasks = getLayerSpacingAndMasks()",Get the spacing and the number of masks of each layer +"def getBlockagesAndRCDisconnectedNets(instanceName): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get all blockages + blockages = block.getBlockages() + + # Get all nets + nets = block.getNets() + + # List to store RC disconnected nets + rcDisconnectedNets = [] + + # Iterate through each net + for net in nets: + # Check if the net is RC disconnected + if net.isRCDisconnected(): + # Append the net to the list of RC disconnected nets + rcDisconnectedNets.append(net) + + # Find the instance by name passed as argument + inst = block.findInst(instanceName) + + # Get the MTerms of the master cell of the specified instance + mterms = inst.getMaster().getMTerms() + + # Return a tuple containing blockages, RC disconnected nets, and MTerms + return (blockages, rcDisconnectedNets, mterms) + +# Call the function with 'rebuffer7' as the argument +blockagesRCDisconnectedNetsMterms = getBlockagesAndRCDisconnectedNets('rebuffer7')","Get all the blockages and get the nets that are RC disconnected, followed by getting the MTerms of the master cell of the instance 'rebuffer7'." +"def getHorizontalLayersAndTechInfo(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # Define the direction for the layers + direction = 'HORIZONTAL' + + # List to store horizontal tech layers and their capacitance + horizontalLayers = [] + + # Iterate through each layer in the technology + for layer in layers: + # Check if the layer direction is HORIZONTAL + if layer.getDirection() == direction: + # Append the layer and its capacitance to the list of horizontal layers + horizontalLayers.append((layer, layer.getCapacitance())) + + # Retrieve the clearance measure + clearanceMeasure = tech.getClearanceMeasure() + + # Get the setting of UseMinSpacingObs in the tech file + minSpaceObs = tech.getUseMinSpacingObs() + + # Construct a dictionary containing horizontal layers, clearance measure, and minimum spacing obstacle + result = { + ""horizontalLayers"": horizontalLayers, + ""clearanceMeasure"": clearanceMeasure, + ""minSpaceObs"": minSpaceObs + } + + # Return the result dictionary + return result + +# Call the function to get horizontal layers and tech info +horizontalLayersTechInfo = getHorizontalLayersAndTechInfo()","Get the horizontal layers and their capacitance, then retrieve the clearance measure system and check if UseMinSpacingObs is set for this technology" +"def getRowAndNetInfo(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get rows and nets + rows = block.getRows() + nets = block.getNets() + + # Dictionary to store row information with row index as key + rowInfoDict = {} + + # Dictionary to store sites of rows with row name as key + rowSiteDict = {} + + # Dictionary to map nets to wires + netWireDict = {} + + # Iterate through each row + for i in range(len(rows)): + row = rows[i] + # Store row information in the rowInfoDict + rowInfoDict[i] = { + ""location"": row.getOrigin(), + ""rotation"": row.getOrient(), + ""direction"": row.getDirection(), + ""spacing"": row.getSpacing() + } + + # Store site of the row in the rowSiteDict + rowSiteDict[row.getName()] = row.getSite() + + # Iterate through each net + for net in nets: + # Map net name to its wire + netWireDict[net.getName()] = net.getWire() + + # Return a tuple containing row information, row sites, and net wire mappings + return (rowInfoDict, rowSiteDict, netWireDict) + +# Call the function to get row and net information +rowAndNetInfo = getRowAndNetInfo()","Get the location, rotation, direction, and spacing of rows as a dictionary with row index as key and get the sites of rows, followed by a dictionary with nets as keys and their wires as values." +"# Get the tapcell and reset it +tap_cell = design.getTapcell() +tap_cell.reset() + +# Get the current block of the design +block = design.getBlock() + +# Find the instance '_411_' +inst = block.findInst('_411_') + +# Set the placement status of the instance to 'UNPLACED' +inst.setPlacementStatus('UNPLACED') + +# Retrieve the capacitor-coupled segments +cc_segs = block.getCCSegs() + +# Return the coupling capacitance segments +return cc_segs","reset the tapcell, set the placement Status of the instance '_411_' to 'UNPLACED' and retrieve the capacitor-coupled segments of the bock" +"# Get the tapcell in the design and reset it +tap_cell = design.getTapcell() +tap_cell.reset() + +# Get the current block of the design +block = design.getBlock() + +# Return all blockages +Blockages = block.getBlockages()",Get all the blockages and reset the tapcell in the design. +"def markOutputNetsAndGetCoordinates(instanceName1, instanceName2): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the instances by names passed as arguments + inst1 = block.findInst(instanceName1) + inst2 = block.findInst(instanceName2) + + # Mark the first output nets of the instances + inst1.getFirstOutput().getNet().setMark(True) + inst2.getFirstOutput().getNet().setMark(True) + + # Get the placement bounding box of the master cell of the instance '_411_' + placementBoundary = inst1.getMaster().getPlacementBoundary() + + # Extract coordinates of the placement bounding box + coordinates = { + ""ul"": placementBoundary.ul(), + ""ll"": placementBoundary.ll(), + ""lr"": placementBoundary.lr(), + ""ur"": placementBoundary.ur() + } + + # Return the coordinates + return coordinates + +# Call the function with '_411_' and 'input1' as arguments +coordinates = markOutputNetsAndGetCoordinates('_411_', 'input1')","Mark the first output nets of the instances '_411_' and 'input1' and get the ul, ll, lr, ur coordinates of the placement bounding box of the master cell of the instance '_411_'." +"def getNonCoreMasterInstancesAndHorizontalLayers(direction): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get all instances + insts = block.getInsts() + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # List to store horizontal tech layers and their capacitance + horizontalLayers = [] + + # List to store instances whose masters are not of type CORE + nonCoreMasterInsts = [] + + # Iterate through each instance + for inst in insts: + # Check if the master cell of the instance is not of type CORE + if not inst.getMaster().isCore(): + # Append the instance to the list of non-core master instances + nonCoreMasterInsts.append(inst) + + # Iterate through each layer in the technology + for layer in layers: + # Check if the layer direction matches the passed direction + if layer.getDirection() == direction: + # Append the layer and its capacitance to the list of horizontal layers + horizontalLayers.append((layer, layer.getCapacitance())) + + # Reset the tapcell + tapCell = design.getTapcell() + tapCell.reset() + + # Return a tuple containing non-core master instances and horizontal layers + return (nonCoreMasterInsts, horizontalLayers) + +# Call the function with 'HORIZONTAL' as the argument +direction = 'HORIZONTAL' +nonCoreMasterInstsAndHorizontalLayers = getNonCoreMasterInstancesAndHorizontalLayers(direction)","Get the instances whose masters are not of type CORE and get the horizontal tech layers and their capacitance, followed by resetting the tapcell" +"def getRectOnlyLayerAliases(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # Initialize a list to store layers that are set as RectOnly + rectLayersAlias = [] + + # Iterate through all layers + for layer in layers: + # Check if the layer is set as RectOnly + if layer.isRectOnly(): + # Append the rectangle-only layer aliases to the list + rectLayersAlias.append(layer.getAlias()) + + # Return the list of rectangle-only layers + return rectLayersAlias + +# Call the function to get the rectangle-only layer aliases +rectLayersAlias = getRectOnlyLayerAliases()",Get the layers that are set as RectOnly and get their alias. +"def getLayerResistanceAndEdgeCapacitance(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # Initialize dictionaries to store resistance and edge capacitance of all layers + layerResistance = {} + layerEdgeCapacitance = {} + + # Iterate through each layer to retrieve resistance and edge capacitance + for layer in layers: + layerResistance[layer.getName()] = layer.getResistance() + layerEdgeCapacitance[layer.getName()] = layer.getEdgeCapacitance() + + # Combine resistance and edge capacitance dictionaries into a single result dictionary + result = { + ""edge_capacitance"": layerEdgeCapacitance, + ""layer_resistance"": layerResistance + } + + # Return the result dictionary + return result + +# Call the function to get the layer resistance and edge capacitance +layerDetails = getLayerResistanceAndEdgeCapacitance()",Get the resistance and edge capacitance of all the layers +"def handlePortAndGetLogicPorts(portName): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Find the port with the given name + port = block.findBTerm(portName) + + # Disconnect the port from the nets it is connected to + port.disconnect() + + # Set the port to special + port.setSpecial() + + # Get the logic ports + logicPorts = block.getLogicPorts() + + # Return the logic ports + return logicPorts + +# Call the function with 'req_val' as the argument to handle the port +logicPorts = handlePortAndGetLogicPorts('req_val')","Disconnect the port named 'req_val' from the nets it is connected to and set the port named 'req_val' to special, and return the logic ports" +"def getUpdatedNetsAndHorizontalLayers(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get all nets + nets = block.getNets() + + # Get the wire updated nets + updatedNets = block.getWireUpdatedNets(nets) + + # Get the technology information + tech = block.getTech() + + # Get all layers defined in the technology + layers = tech.getLayers() + + # List to store horizontal layers in the technology file + horizontalLayers = [] + + # Iterate through each layer in the technology + for layer in layers: + # Check if the layer direction is 'HORIZONTAL' + if layer.getDirection() == 'HORIZONTAL': + # Append the horizontal layer to the list + horizontalLayers.append(layer) + + # Create a dictionary containing updated nets and horizontal layers + result = { + ""nets"": updatedNets, + ""layers"": horizontalLayers + } + + # Return the result dictionary + return result + +# Call the function to get updated nets and horizontal layers +updatedNetsAndLayers = getUpdatedNetsAndHorizontalLayers()",Get all the wire_updated nets and get the horizontal layers +"def getLayerAndPortInfo(): + # Assuming `design.getBlock()` and similar functions are available in the environment + block = design.getBlock() # Get the block + + # Get the technology information + tech = block.getTech() + + # Get the count of layers + layerCount = tech.getLayerCount() + + # Get the Routing Layer Count + routingLayerCount = tech.getRoutingLayerCount() + + # Get the logic ports + logicPorts = block.getLogicPorts() + + # Create a dictionary containing layer count, routing layer count, and logic ports + result = { + ""layer_count"": layerCount, + ""routing_layer_count"": routingLayerCount, + ""logic_ports"": logicPorts + } + + # Return the result dictionary + return result + +# Call the function to get layer count, routing layer count, and logic ports +layerAndPortInfo = getLayerAndPortInfo()","Get the count of layers and get the routing layer count, along with the logic ports" +"# Get the current block of the design +block = design.getBlock() + +# Find the net with name ""req_msg[11]"" +net1 = block.findNet(""req_msg[11]"") +# Set the Capacitance Coupling Adjust Factor to 1 +net1.setCcAdjustFactor(1) + +# Find the net with name ""req_msg[12]"" +net2 = block.findNet(""req_msg[12]"") +# Set the Capacitance Coupling Calibration Factor to 2 +net2.setCcCalibFactor(2)","Set the Capacitance Coupling Adjust Factor of the net with name ""req_msg[11]"" to 1 and set the Capacitance Coupling Calib Factor of the net with name ""req_msg[12]"" to 2." +"def getClockPins(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the pins (which are also called Iterms in OpenROAD) + pins = block.getITerms() + + result = [] + + # Iterate through all the pins + for pin in pins: + # Check if the pin is in clock + if design.isInClock(pin.getInst()): + # Append the pin to the result + result.append(pin) + + # Return the list of clock pins + return result + +# Call the function to get the clock pins +clockPins = getClockPins()",Get all the Pins which are in clock net as a list. +"def getInstanceBBox(instance_name): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Find the instance with the given name + inst = block.findInst(instance_name) + + # Get the Bounding box of the instance + BBox = inst.getBBox() + + # Get the X Minimum of the Bounding Box of the instance + xmin = BBox.xMin() + + # Get the Y Minimum of the Bounding Box of the instance + ymin = BBox.yMin() + + # Get the X Maximum of the Bounding Box of the instance + xmax = BBox.xMax() + + # Get the Y Maximum of the Bounding Box of the instance + ymax = BBox.yMax() + + # Return the coordinates of the bounding box + return [[xmin, ymin], [xmax, ymax]] + +# Call the function with the instance name ""input1"" +instanceBBox = getInstanceBBox(""input1"")","Get the Bounding Box of an instance named ""input1"". Return a list of coordinates (Xmin, Ymin in one list and Xmax, Ymax in next list) " +"def getLibrariesAndCells(db): + # Get all the libraries in the database + libs = db.getLibs() + library_cells_dict = {} + + # Iterate through all the libraries + for lib in libs: + # Get the library cells of the library + master_cells = lib.getMasters() + cells = [] + + # Iterate through all the library cells + for master in master_cells: + # Append the library cell to the cells list + cells.append(master) + + # Add the library name and its cells to the dictionary + library_cells_dict[lib.getName()] = cells + + return library_cells_dict + +# Example of how to call the function +libraries_and_cells = getLibrariesAndCells(db)",Get all the library cells as a dictionary of list. Key of the dictionary is library name and the value is the list of all the library cells in the library file +"def getLibraryCellNames(db): + # Get all the libraries in the database + libs = db.getLibs() + libcell_name_list = [] + + # Iterate through all libraries + for lib in libs: + # Get all library cells in this library file + lib_masters = lib.getMasters() + + # Iterate through all library cells + for master in lib_masters: + # Get the name of the library cell + libcell_name = master.getName() + # Add the name to the list + libcell_name_list.append(libcell_name) + + return libcell_name_list + +# Example of how to call the function +library_cell_names = getLibraryCellNames(db)",Get the name of every liberty cell +"def get_instance_orientations(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + orientation = [] + + # Retrieve all instances present in the design block + insts = block.getInsts() + + # Iterate over each instance in the design block + for inst in insts: + # Append the name and orientation of the instance + orientation.append([inst.getName(), inst.getOrient()]) + + return orientation + +# Call the function and store the result +instance_orientations = get_instance_orientations()",Get the rotations of all instances as a list of lists +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst('input1') +# Set the rotation of the instance as ""MX"" +inst.setOrient('MX')",Set the rotation of an instance 'input1' as 'MX' +"def get_output_nets(instance_name): + # Get the current block from the design + block = design.getBlock() + + # Retrieve the instance within the design + inst = block.findInst(instance_name) + + # Initialize a list to store the net of the output pin + output_nets = [] + + pins = inst.getITerms() + + # Iterate through each pin of the instance + for pin in pins: + # Check if the pin represents an output signal + if pin.isOutputSignal(): + # Retrieve the net associated with this output pin + net = pin.getNet() + # If net is not None then append it to the output_nets + if net: + output_nets.append(net) + + return output_nets + +# Call the function with the desired instance name +output_nets_for_instance = get_output_nets('output53')",get the nets of the output pins of the instance 'output53' +"def get_instance_bbox_dimensions(instance_name): + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Get the Bounding Box + bounding_box = inst.getBBox() + + # Get the DX and DY of the Bounding Box of the instance + return (bounding_box.getDX(), bounding_box.getDY()) + +# Call the function with the desired instance name +bbox_dimensions = get_instance_bbox_dimensions('_411_')",Get the width and height of the bounding box of instance '_411_' +"# Set the level of all 'AND2_X1' gate instances in the design to 1 + +# Get the design block +block = design.getBlock() + +# Get all instances +insts = block.getInsts() + +# Iterate through all instances +for inst in insts: + # Check if the instance's master name contains 'AND2_X1' + if inst.getMaster().getName() == 'AND2_X1': + # Set the level of the instance to 1 + inst.setLevel(1, False)",set the level of all 'AND2_X1' gate instance in the design to 1 +"def get_lower_left_corners(cell_type): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store the coordinates of the lower-left corner of the bounding box of the instances + inst_to_master_transform_offset = {} + + # Iterate through all instances + for inst in insts: + # Check if the name of the library cell type matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Add the instance name and the coordinates of the lower-left corner of the bounding box to the dictionary + inst_to_master_transform_offset[inst.getName()] = inst.getTransform().getOffset() + + return inst_to_master_transform_offset + +# Call the function with 'AND2_X1' as the argument +and2_x1_coordinates = get_lower_left_corners('AND2_X1')",Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' +"def get_lower_left_corners(cell_type): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store the coordinates of the lower-left corner of the bounding box of the instances + inst_to_master_transform_offset = {} + + # Iterate through all instances + for inst in insts: + # Check if the name of the library cell type matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Add the instance name and the coordinates of the lower-left corner of the bounding box to the dictionary + inst_to_master_transform_offset[inst.getName()] = inst.getOrigin() + + return inst_to_master_transform_offset + +# Call the function with 'AND2_X1' as the argument +and2_x1_coordinates = get_lower_left_corners('AND2_X1')",Get the coordinates of the lower-left corner of the bounding box of the instances whose library cell type is 'AND2_X1' +"def get_instance_orientations(cell_type): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store the orientation of instances + inst_to_master_transform_orient = {} + + # Iterate through all instances + for inst in insts: + # Check if the master name matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Add the instance name and its orientation to the dictionary + inst_to_master_transform_orient[inst.getName()] = inst.getTransform().getOrient() + + return inst_to_master_transform_orient + +# Call the function with 'AND2_X1' as the argument +and2_x1_orientations = get_instance_orientations('AND2_X1')",Retrieve the rotation of instances that have 'AND2_X1' as their library cell type. +"def get_instance_orientations(cell_type): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store the orientation of instances + inst_to_master_transform_orient = {} + + # Iterate through all instances + for inst in insts: + # Check if the master name matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Add the instance name and its orientation to the dictionary + inst_to_master_transform_orient[inst.getName()] = inst.getOrient() + + return inst_to_master_transform_orient + +# Call the function with 'AND2_X1' as the argument +and2_x1_orientations = get_instance_orientations('AND2_X1')",Retrieve the rotation of instances that have 'AND2_X1' as their library cell type. +"def get_instance_first_output_pins(): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Initialize a dictionary to store instances and their output pins + inst_outputs = {} + + # Iterate through all instances + for inst in insts: + # Add the instance name and its first output pin to the dictionary + inst_outputs[inst.getName()] = inst.getFirstOutput() + + return inst_outputs + +# Call the function to get the instance output pins +instance_output_pins = get_instance_first_output_pins()",Get the first output pin of an instance and map it to the instance names as the value in the dictionary. +"def set_user_flags_for_instance(instance_name): + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Set the user-defined flags 1 and 3 to true + inst.setUserFlag1() + inst.setUserFlag3() + + # Return the modified instance + return inst + +# Call the function with the desired instance name +modified_instance = set_user_flags_for_instance('_411_')",Set the user-defined flags 1and 3 to true for instance '_411_' and return the instance +"def get_placement_bounding_box_coordinates(instance_name): + # Get the design block + block = design.getBlock() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Get the master cell associated with the instance + master = inst.getMaster() + + # Get the placement bounding box of the master cell + placement_boundary = master.getPlacementBoundary() + + # Get the coordinates of the placement bounding box + # Upper Left placement bounding box + ul = placement_boundary.ul() + # Lower Left placement bounding box + ll = placement_boundary.ll() + # Lower Right placement bounding box + lr = placement_boundary.lr() + # Upper Right placement bounding box + ur = placement_boundary.ur() + + # Return the coordinates as a list + coordinates = [ul, ur, lr, ll] + return coordinates + +# Call the function with the desired instance name +placement_coordinates = get_placement_bounding_box_coordinates('_411_')","get the upper left, upper right, lower left, lower right coordinates of the placement bounding box of the master cell of the instance '_411_'" +"def check_instance_and_collect_hierarchical_instances(instance_name, target_master_name): + # Get the current block of the design + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Find the specified instance + inst = block.findInst(instance_name) + + # Check if the instance is of type ENDCAP or any of its subtypes + inst_is_endcap = inst.isEndCap() + + # Clear user-defined flags of the specified instance + inst.clearUserFlag1() + inst.clearUserFlag2() + inst.clearUserFlag3() + + # List to store instances having hierarchy and whose library cell name matches the target + inst_list = [] + + # Iterate through each instance + for inst in insts: + # Check if the instance is hierarchical, its library cell name matches the target, and is level 1 + if inst.isHierarchical() and inst.getMaster().getName() == target_master_name and inst.getLevel() == 1: + # Append the instance to the list + inst_list.append(inst) + + # Return a tuple containing the status of the specified instance and the list of hierarchical instances + return (inst_is_endcap, inst_list) + +# Call the function with the desired instance name and target master name +result = check_instance_and_collect_hierarchical_instances('_411_', 'AND2X_1')","Check if the instance '_411_' is type ENDCAP or any of its subtypes, and clear user-defined flags of instance '_411_', then get all the instances with hierarchicy and whose library cell is AND2X_1 and the instance is level 1." +"def get_instance_design_block(instance_name): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Find the instance with the specified name + inst = block.findInst(instance_name) + + # Return the corresponding design block of the instance + return inst.getBlock() + +# Call the function with the desired instance name +design_block = get_instance_design_block('input1')","Given the instance name 'input1', get the design block this instance belongs to." +"def get_db_units_per_micron(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Return the DB units per micron + return block.getDbUnitsPerMicron() + +# Call the function to get the DB units per micron +db_units_per_micron = get_db_units_per_micron()",Convert 1 um to units used in this technology in OpenROAD +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the DEF units of this technology +DefUnit = block.getDefUnits()",Get the DEF units of this technology. +"def get_db_rows_info(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the DB rows + rows = block.getRows() + d = {} + + # Iterate through all the rows + for row in rows: + # Get the name of the DB row + name = row.getName() + # Get the spacing of the DB row + spacing = row.getSpacing() + # Store the row information in the dictionary + d[row] = [name, spacing] + + return d + +# Call the function to get the database rows information +db_rows_info = get_db_rows_info()","Get the rows with its name and spacing in a form of a dictionary. The key of the dictionary is the row object, the value is a list containing name and spacing of the row object" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Set the unit used in def file to 3000 as mentioned in the prompt +block.setDefUnits(3000)",Set the def units per micron to 3000 +"def get_module_names(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the modules + modules = block.getModules() + module_names = [] + + # Iterate through all the modules + for module in modules: + # Append the names of the module + module_names.append(module.getName()) + + return module_names + +# Call the function to get the module names +module_names_list = get_module_names()",Get all the modules and return the names of modules as a list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst(""inpu1"") +inst.setUserFlag1()","Set user-defined flag 1 to ture on the instance with name ""input1""" +"def get_net_cc_adjust_factors(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the nets + nets = block.getNets() + adjust_factors = [] + + # Iterate through all the nets + for net in nets: + # Append the capacitance coupling adjust factor of the net + adjust_factors.append(net.getCcAdjustFactor()) + + return adjust_factors + +# Call the function to get the capacitance coupling adjust factors +net_adjust_factors = get_net_cc_adjust_factors()",Get the capacitance coupling Adjust Factor of every net and return them as a list. +"def get_net_cc_adjust_orders(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the nets + nets = block.getNets() + adjust_orders = [] + + # Iterate through all the nets + for net in nets: + # Append the capacitance coupling adjust order of the net + adjust_orders.append(net.getCcAdjustOrder()) + + return adjust_orders + +# Call the function to get the capacitance coupling adjust orders +net_adjust_orders = get_net_cc_adjust_orders()",Get the capacitance coupling Adjust Order of every net and return them as a list. +"def get_net_tracks(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the nets + nets = block.getNets() + track_list = [] + + # Iterate through all the nets + for net in nets: + # Get the tracks of the net + tracks = net.getTracks() + # Append the tracks to the track list + track_list.append(tracks) + + return track_list + +# Call the function to get the tracks for all nets +net_tracks = get_net_tracks()",Get the tracks of every net as a list of lists. Each list in the output list should contain the tracks of respective net +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the instance with name 'input1' as mentioned in the prompt +inst = block.findInst(""input1"") +# Get the nets of the instance +nets = inst.getNets() +track_list = [] +# Iterate through all the nets +for net in nets: + # Get the tracks of the net + tracks = net.getTracks() + track_list.append(tracks)","Get the tracks of nets that are connected to instance with name ""input1"" as a list of list. Each list in the output list should contain the tracks of respective net" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the nets +nets = block.getNets() +types = [] +# Iterate through all the nets +for net in nets: + # Append the wire type of the net + types.append(net.getWireType())",Get the wire type of each net and return them as a list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the nets +nets = block.getNets() +termsCount = [] +# Iterate through all the nets +for net in nets: + # Get term counts of the net and append to the array + termsCount.append(net.getTermCount())",Get term count of every net and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +output = [] +insts = block.getInsts() +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rise arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is greater than 0.5 second as mentioned in the prompt + if pin_rise_arr > 0.5: + output.append(pin)",Get all the pins which has the rising arrival time greater than 0.5 sec and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +insts = block.getInsts() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the rising arrival time + pin_rise_arr = timing.getPinArrival(pin, timing.Rise) + # Check if the rising arrival time is less than or equal 0.5 second as mentioned in the prompt + if pin_rise_arr <= 0.5: + output.append(pin)",Get all the pins which has the rising arrival time less than or equal to 0.5 second and return them as list +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +insts = block.getInsts() +output = [] +# Iterate through all the instances +for inst in insts: + # Get all the pins connected to the instance + inst_ITerms = inst.getITerms() + # Iterate through the pins + for pin in inst_ITerms: + if design.isInSupply(pin): + continue + # Get the falling arrival time + pin_fall_arr = timing.getPinArrival(pin, timing.Fall) + # Check if the fall arrival time is greater than 0.8 second as mentioned in the prompt + if pin_fall_arr > 0.8: + # Append the pin to the output + output.append(pin)",Get all the pins which has Pin Fall Arrival Time greater than 0.8 sec and return them as list +"def check_if_any_wire_altered(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the nets + nets = block.getNets() + + # Iterate through all the nets + for net in nets: + # Check if the wire is replaced with a new wire + if net.isWireAltered(): + return True + + return False + +# Call the function to check if any wire is altered +is_wire_altered = check_if_any_wire_altered()",Check all the nets and check if any of its wires is replaced with a new wire. Return True if Altered and false otherwise +"def get_ports_and_nets(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the ports (which are known as BTerms in OpenROAD) + ports = block.getBTerms() + port_net_dict = {} + + # Iterate through all the ports + for port in ports: + # Append the name and net of the port in the dictionary + port_net_dict[port.getName()] = port.getNet() + + return port_net_dict + +# Call the function to get the ports and their associated nets +ports_and_nets = get_ports_and_nets()",Get all the net of ports and return a dictionay with port name as key and Net of the port as Value of the dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +# Iterate through all the ports +for port in ports: + # Append the name and block pins objects of the port in the dictionary + d[port.getName()] = port.getBPins()",Get all the design block pins objects of ports and return a dictionay with port name as key and pins of the port as Value of the dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the design block ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +placement_status_with_name = {} +# Iterate through all the ports +for port in ports: + # Get the name of the port + name = port.getName() + # Get the placement status of the port + status = port.getFirstPinPlacementStatus() + # Append the placement status and name of the port to the dictionary + placement_status_with_name[name] = status",Get the name of every design block port with the placement status of the first pin as a dictionary +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the ports (which are known of BTerms in OpenROAD) +ports = block.getBTerms() +d = {} +output = [] +# Iterate through all the ports +for port in ports: + # Append the port name and IO type of the port to the dictionary + d[port.getName()] = port.getIoType()",Get all the I/O types of ports and return a dictionay with port name as keys and IO Type of the port as values +"def get_port_bounding_box(port_name=""req_val""): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Find the port with the specified name + port = block.findBTerm(port_name) + + # Find the boundary box of the port + BBox = port.getBBox() + + # Get the coordinates of the bounding box + xmin = BBox.xMin() + ymin = BBox.yMin() + xmax = BBox.xMax() + ymax = BBox.yMax() + + return [[xmin, ymin], [xmax, ymax]] + +# Call the function to get the bounding box of the port ""req_val"" +bounding_box = get_port_bounding_box()","Get the Bounding Box of a port named ""req_val"". Return a list of coordinates (Xmin, Ymin in one list and Xmax, Ymax in another list) " +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Set SPECIAL attribute to the port +port.setSpecial()",Set SPECIAL attribute port named 'req_val' +"def is_port_special(port_name): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Find the port with the specified name + port = block.findBTerm(port_name) + + # Return whether the port has the SPECIAL attribute + return port.isSpecial() + +# Call the function with the argument ""req_val"" +port_special_status = is_port_special('req_val')",Check if the port named 'req_val' has SPECIAL attribute +"def get_wire_updated_nets(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get all the nets + nets = block.getNets() + + # Get and report wire-updated nets + wire_updated_nets = block.getWireUpdatedNets(nets) + + return wire_updated_nets + +# Call the function to get wire-updated nets +updated_nets = get_wire_updated_nets()",Get the of nets for any wire changes and report the statistics of the nets with changed wires. +"def get_technology_layers(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Return the technology layers + return tech.getLayers() + +# Call the function to get the technology layers +technology_layers = get_technology_layers()",Get the technolgy layers. The layers are ordered from the bottom mask number to the top mask number. +"def get_layer_count(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Return the number of layers in this technology + return tech.getLayerCount() + +# Call the function to get the layer count +layer_count = get_layer_count()",Get the number of layers in this technology. +"def get_routing_layer_count(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Return the number of routing layers in this technology + return tech.getRoutingLayerCount() + +# Call the function to get the routing layer count +routing_layer_count = get_routing_layer_count()",Get the number of routing-layers in this technology. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the number of vias in this technolgy. +viaCount = tech.getViaCount()",Get the number of vias in this technolgy. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return the via generate rules in this technolgy +viaGenerateRule = tech.getViaGenerateRules()",Get the via generate rules in this technolgy. +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get the technolgy vias. This includes non-default-rule-vias. +vias = tech.getVias()",Get the technolgy vias +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get LEF CLEARANCEMEASURE +clearanceMeasure = tech.getClearanceMeasure()",Get LEF CLEARANCEMEASURE +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Return MANUFACTURINGGRID +# NOTE: Assumes conversion to internal DB units, +# NOT microns or LEF/DEF units +ManufacturingGrid = tech.getManufacturingGrid()",Get MANUFACTURINGGRID +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the net with name ""req_msg[11]"" +net = block.findNet(""req_msg[11]"") +# Set the capacitance coupling adjust factor of the net to 1 +net.setCcAdjustFactor(1)","Set the capacitance coupling adjust factor of the net with name ""req_msg[11]"" to 1" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the net with name ""req_msg[11]"" +net = block.findNet(""req_msg[11]"") +# Set the capacitance coupling calibration factor of the net to 2 +net.setCcCalibFactor(2)","Set the capacitance coupling calibration factor of the net with name ""req_msg[11]"" to 2" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get all the nets +nets = block.getNets() +output = {} +# Iterate through all the nets +for net in nets: + # Append the net name and capacitance coupling match ratio against the net to a dictionary + output[net.getName()] = net.getCcMatchRatio()",Get the capacitance coupling match ratio against this nets with the name of the net. Return a dictionary with key being the name of the net and value of the dictionary is the capacitance coupling match ratio against the net +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Iterate through the net names ""req_msg[13] and ""clk"" as mentioned in the prompt +for net_name in [""req_msg[13]"", ""clk""]: + # Find the net with net name as parameter + net = block.findNet(net_name) + # Set the coupling capacitance match ratio against the net to 1 + net.setCcMatchRatio(1)","Set the coupling capacitance match ratio against the net with name ""req_msg[13]"" and ""clk"" to 1" +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get the technology layers +layers = tech.getLayers() +output = [] +# Iterate through all the layers +for layer in layers: + # Get the names of the technology layers + output.append(layer.getName())",Get the names of the technology layers +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get all the tehnology layers +layers = tech.getLayers() +output = {} +# Iterate through all the technology layers +for layer in layers: + # Append the layer name and AREA parameter to the dictionary + output[layer.getName()] = layer.getArea()",Get the AREA parameter of the technology layers with their name. Return a dictionary with key as the layer name and value as the AREA parameter +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Get all the technology layers +layers = tech.getLayers() +output = {} +# Iterate through all the layers +for layer in layers: + # Append the layer name and layer direction to the dictionary + output[layer.getName()] = layer.getDirection()",Get the directions of the technology layers with their name. Return a dictionary with key as the layer name and value as the layer direction +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Get the technology information +tech = block.getTech() +# Find the layer with name 'metal8' +layer = tech.findLayer('metal8') +# Return the routing layer corner spacing rule +techLayerCornerSpacingRules = layer.getTechLayerCornerSpacingRules()",Get the routing layer corner spacing rules of technology layer with name 'metal8' +"# Get the design block +block = ord.get_db_block() +# Find the instance named ""split30"" +split30 = block.findInst(""split30"")",Find instance split30 +"def get_instance_names(): + # Get the design block + block = ord.get_db_block() + + # Get instances + insts = block.getInsts() + + # Initialize a list to store instance names + inst_names = [] + + # Iterate over instances and append their names to the list + for inst in insts: + inst_names.append(inst.getName()) + + return inst_names + +# Call the function +instance_names = get_instance_names()",List all the instances name +"# Define the function to select nets +def get_selected_nets(): + # Get the design block + block = design.getBlock() + + # Get all nets + nets = block.getNets() + + # List to store selected nets + selected_nets = [] + + # Iterate through each net + for net in nets: + # Check if the net is selected + if net.isSelect(): + # Append the net to the list + selected_nets.append(net) + + return selected_nets + +# Call the function +selected_nets = get_selected_nets()",Get the selected nets +"def get_cut_class_rules(layer_name='metal8'): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + + # Get the technology information + tech = block.getTech() + + # Find the technology layer with the given name + layer = tech.findLayer(layer_name) + + # Return the cut layer class rule + return layer.getTechLayerCutClassRules() + +# Calling the function with the default 'metal8' layer +cut_class_rules = get_cut_class_rules()",Get the cut layer class rule of layer with name 'metal8' +"def set_wire_type_as_routed(design, nets): + # Get the design block + block = design.getBlock() + + # Iterate through each net name + for name in nets: + # Find the net object by name + net = block.findNet(name) + + # Set the wire type of the net as ROUTED + net.setWireType('ROUTED') + +# List of net names to set wire type as ROUTED +nets = [ + ""_000_"", + ""_001_"", + ""_002_"", + ""_003_"", + ""_004_"", + ""_005_"", + ""_006_"", + ""_007_"", + ""_008_"", + ""_009_"", + ""_010_"" +] + +# Assuming `design` is an object that's already available +set_wire_type_as_routed(design, nets)","Set the following nets wire type to ROUTED: _000_, _001_, _002_, _003_, _004_, _005_, _006_, _007_, _008_, _009_, _010_ +" +"def get_port_signals(block=None): + if block is None: + block = ord.get_db_block() # Default to current database block if no block is provided. + + ports = block.getBTerms() + port_signals = {} + + for port in ports: + port_signals[port.getName()] = port.getSigType() + + return port_signals + +# Call the function +port_signals = get_port_signals() +print(port_signals)",Get the name of every block port with its signal type as a dictionary +"def check_output_pins_without_nets(): + # Get the design block + block = ord.get_db_block() + # Get all instances + insts = block.getInsts() + # Initialize a list to store output pins without nets + outputPinWithoutNet = [] + + # Iterate over instances + for inst in insts: + # Get all pins of the instance + pins = inst.getITerms() + # Iterate over pins + for pin in pins: + # Check if the pin is an output signal + if pin.isOutputSignal(): + # Get the net connected to the pin + nets = pin.getNet() + # Check if the pin has no net connected + if nets is None: + # Append the pin to the list + outputPinWithoutNet.append(pin) + + # Check if there are no output pins without nets + return len(outputPinWithoutNet) == 0 + +# Call the function +result = check_output_pins_without_nets() +print(""No output pins without nets:"" if result else ""Output pins without nets found."")",Check if all the output pins of all instances have a valid net connection +"def get_instance_locations(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + # Retrieve all instances present in the design block + insts = block.getInsts() + loc = [] + for inst in insts: + # Append the location of the instance to the list + loc.append(inst.getLocation()) + return loc + +# Call the function +locations = get_instance_locations()",Give me the location of every instance in the design and return it in a list called loc. +"def get_placement_status(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + # Retrieve all instances present in the design block + insts = block.getInsts() + placement_status_with_name = {} + # Iterate over each instance in the design block + for inst in insts: + # Get the name of the particular instance + name = inst.getName() + # Get the placement status of the instance + status = inst.getPlacementStatus() + # Add the respective instance name and its status + placement_status_with_name[name] = status + return placement_status_with_name + +# Call the function +placement_status = get_placement_status()",Get the name of every instance with its placement status as a dictionary +"def get_placed_instances(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + # Retrieve all instances present in the design block + insts = block.getInsts() + placed_instances = [] + # Iterate over each instance in the design block + for inst in insts: + # Check if this instance is placed + if inst.isPlaced() == True: + # Append the instance name to the array + placed_instances.append(inst.getName()) + return placed_instances + +# Call the function +placed_instances_list = get_placed_instances()",Get the names of every instance which are placed and return a list of names +"def get_net_cap_res_coupling(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + # Retrieve all nets present in the design block + nets = block.getNets() + result = [] + # Iterate over each net in the design block + for net in nets: + # Check the signal type of the net + if net.getSigType() != 'POWER' and net.getSigType() != 'GROUND': + # Get the name of the net + net_name = net.getName() + # Get the total Capacitance of the net + net_cap = net.getTotalCapacitance() + # Get the total resistance of the net + net_res = net.getTotalResistance() + # Get the total coupling capacitance of the net + net_coupling = net.getTotalCouplingCap() + # Append the net name, net capacitance, net resistance, and net coupling + result.append([net_name, net_cap, net_res, net_coupling]) + return result + +# Call the function +net_info = get_net_cap_res_coupling()","Get the total capacitance, total resistance, Coupling Capacitance of all the nets except the nets that are connected to Ground and Power External Power Supply. Get them as list of lists, in which each list contains the net name, net capacitance, net resistance and net coupling." +"def get_nets_with_no_pins(): + # Get the current design block from the OpenROAD database + block = ord.get_db_block() + # Retrieve all nets present in the design block + nets = block.getNets() + result = [] + # Iterate over each net in the design block + for net in nets: + # Get the Pins of the net + pins = net.getITerms() + # Check if the length of the number of pins of the net is Zero + if len(pins) == 0: + # Append the net to the result + result.append(net) + return result + +# Call the function +nets_with_no_pins = get_nets_with_no_pins()",Get all the nets which are not connected to any pins and return them as list. +"def flip_nand2_instances(cell_type): + # Define the flipping function + def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270"" + + # Get the design block + block = design.getBlock() + + # Get all instances in the block + insts = block.getInsts() + + # Iterate through all instances in the block + for inst in insts: + # Check if the library cell type matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Horizontally flip the rotation of the instance + orient = inst.getTransform().getOrient() + orient = flipX(orient) + inst.setOrient(orient) + +# Call the function with the hard-coded 'NAND2_X1' cell type +flip_nand2_instances('NAND2_X1')",Horizontally flip the rotation of the instances whose library cell types are 'NAND2_X1' +"def flip_and2_instances(cell_type): + # Define the flipping function + def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90"" + + # Get the design block + block = design.getBlock() + + # Get all instances in the block + insts = block.getInsts() + + # Iterate through all instances in the block + for inst in insts: + # Check if the library cell type matches the provided cell_type + if inst.getMaster().getName() == cell_type: + # Vertically flip the rotation of the instance + orient = inst.getOrient() + orient = flipY(orient) + inst.setOrient(orient) + +# Call the function with the hard-coded 'AND2_X1' cell type +flip_and2_instances('AND2_X1')",Vertically flip the rotation of the instances whose library cell types are 'AND2_X1' +"# Get the current design block from the OpenROAD database +block = ord.get_db_block() +# Find the port with name ""req_val"" +port = block.findBTerm('req_val') +# Find the net with name ""req_msg[17]"" +net = block.findNet('req_msg[17]') +# Connect the port and the net +port.connect(net)",Connect the port named 'req_val' and net named 'req_msg[17]' +"def swap_instance_master(instance_name, new_master_name): + # Get the design block + block = ord.get_db_block() + # Get the database + db = ord.get_db() + # Find the instance by its name + inst = block.findInst(instance_name) + # Check if the required library cell exists in the database + if db.findMaster(new_master_name) is not None: + # Find the required library cell + new_mast = db.findMaster(new_master_name) + # Swap the instance's library cell with the new library cell + inst.swapMaster(new_mast) + return True + else: + return False + +# Call the function with hard-coded arguments +instance_swapped = swap_instance_master(""split30"", ""BUF_X4"")",Upsize the instance split30 to BUF_X4 +"def invert_transform_and_get_offset(instance_names, master_cell_name): + # Get the design block + block = design.getBlock() + + # Get all instances + insts = block.getInsts() + + # Dictionary to store offset of transforms for specific instances + inst_transform_offset = {} + + # Iterate through instances + for inst in insts: + # Check if the master cell name matches the provided master_cell_name + if inst.getMaster().getName() == master_cell_name: + # Get transform and invert + transform = inst.getTransform() + transform.invert() + + # Check if instance name is in the provided instance_names list + if inst.getName() in instance_names: + # Get transform and store offset + transform = inst.getTransform() + inst_transform_offset[inst.getName()] = transform.getOffset() + + return inst_transform_offset + +# Call the function with hard-coded arguments +instance_offsets = invert_transform_and_get_offset(['_411_', 'input1'], 'NAND2_X1')","Invert the location and rotation of instances whose library cells are 'NAND2_X1'. Then, retrieve the location of the instances '_411_' and 'input1' and return them as a dictionary with the instance names as keys and their respective location as values." +"# Set the rotation of the instance '_411_' to 'MX' + +# Get the design block +block = design.getBlock() + +# Find the instance with the specified name +inst = block.findInst('_411_') + +# Set the rotation of the instance to 'MX' +transform = inst.getTransform() +transform.setOrient('MX') +inst.setTransform(transform)",Set the rotation of the instance '_411_' to 'MX' +"def get_input_pins_for_instance(instance_name): + # Get the design block + block = design.getBlock() + + # Find the instance by name + inst = block.findInst(instance_name) + + # Initialize a list to store the input pins of the instance + input_pins = [] + + # Obtain all pins associated with this instance + pins = inst.getITerms() + + # Iterate through each pin of the instance + for pin in pins: + # Check if the pin represents an input signal + if pin.isInputSignal() and pin: + # Append the input pin to the list of input pins + input_pins.append(pin) + + return input_pins + +# Call the function with the hard-coded 'output53' instance name +input_pins_for_output53 = get_input_pins_for_instance('output53')",get the input pins of the instance 'output53' +"# Get the design block +block = ord.get_db_block() +# Find the instance ""_split30_"" +inst = block.findInst(""_split30_"") +# Set the instance as don't touch type +inst.setDoNotTouch(False)","Reset the instance ""_split30_"" as don't touch type" \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.xlsx b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.xlsx new file mode 100644 index 0000000..c3d737e Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/DB_Dataset.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.csv b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.csv new file mode 100644 index 0000000..60daaa9 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.csv @@ -0,0 +1,31931 @@ +code,prompt +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk_i"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a gate-level netlist with a clock port called ""clk"", read the tech file, lef files, and library files, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 30. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 50% +floorplan_utilization = 50 +# Set the aspect ratio of the design (height/width) as 1 +floorplan_aspect_ratio = 1 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 50%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 10 +floorplan_core_spacing = [design.micronToDBU(10) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 10 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 10. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(15, 30, 10, 40) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 15 um,10 um, and the top-right corner as 30 um,40 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After placement, do CTS and use BUF_X3 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 40 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(40), design.micronToDBU(60)) +core_area = odb.Rect(design.micronToDBU(10), design.micronToDBU(10), + design.micronToDBU(30), design.micronToDBU(50)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 40,60. Set the bottom-left corner of the core's bounding box as 10,10 and the top-right corner as 30,50. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 20 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform CTS with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 50 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(70), design.micronToDBU(70)) +core_area = odb.Rect(design.micronToDBU(6), design.micronToDBU(6), + design.micronToDBU(64), design.micronToDBU(64)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 20 times +gpl.setInitialPlaceMaxIter(20) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_spacing = [design.micronToDBU(4), design.micronToDBU(4)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 50 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 70,70. Set the bottom-left corner of the core's bounding box as 6,6 and the top-right corner as 64,64. After floorplanning, place the standard cells and the macros. Place each macro at least 5 um away from each other, and set a halo region around each macro as 5 um. Set the number of iteration of the global router as 20. During detailed placement, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 4 and 4 um, and for the power rings on M8, set the width and spacing to 4 and 4 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +core_area = odb.Rect(design.micronToDBU(8), design.micronToDBU(8), + design.micronToDBU(52), design.micronToDBU(42)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a placed design with a clk port called ""clk_i"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,50. Set the bottom-left corner of the core's bounding box as 8,8 and the top-right corner as 52,42. After floorplanning, place the macros and the standard cells. Make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M6. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 45% +floorplan_utilization = 45 +# Set the aspect ratio of the design (height/width) as 1.5 +floorplan_aspect_ratio = 1.5 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(32, 55, 32, 60) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M2"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk_i"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 45%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 32 um,32 um, and the top-right corner as 55 um,60 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform clock tree synthesis with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M6. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile make sure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 14 +floorplan_core_spacing = [design.micronToDBU(14) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 14 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as1. After the placement stage, perform CTS with using BUF_X3 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.0435 and 0.0817, respectively. Then construct PDN with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 2 um and set the spacing to 2 um. And if there are parallel grids, set the pitch of the via between two grids to 2 um. Last, set the offset to 0 for all cases. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 60% +floorplan_utilization = 60 +# Set the aspect ratio of the design (height/width) as 1.3 +floorplan_aspect_ratio = 1.3 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_spacing = [design.micronToDBU(1.5), design.micronToDBU(1.5)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +macro_ring_connect_to_pad_layers = [l for l in design.getTech().getDB().getTech().getLayers() if l.getType() == ""ROUTING""] +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = macro_ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""PDN.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 60%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. During detailed placement, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After placement, do CTS and use BUF_X2 as clock buffers, then set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power rings and power grids for macros on M5 and M6 , set the width and spacing of both the M5 and the M6 grids to 1.2 um, and set the pitch to 6 um. For the power ring on M5 and M6, set the width to 1.5 um and set the spacing to 1.5 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After PDN construction, get the IR drop analysis result on M1 layer and dump the def file and name it ""PDN.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 5 +floorplan_core_spacing = [design.micronToDBU(5) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 5 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, dump the def file and name it ""placement.def"". " +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In the end, dump the def file and name it ""final.def""." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 40% +floorplan_utilization = 40 +# Set the aspect ratio of the design (height/width) as 0.66 +floorplan_aspect_ratio = 0.66 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +design.writeDef(""floorplan_place_pins.def"") + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +design.writeDef(""global_placement.def"") + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(18, 43, 12, 42) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +design.writeDef(""macro_placement.def"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""detailed_placement.def"") + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""cts.def"") + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +design.writeDef(""filler_placement.def"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +design.writeDef(""PDN.def"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +# Report Power + +design.evalTclString(""report_power"") + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +design.writeDef(""final.def"") + +","Given a synthesized netlist with a clock port named ""clk"", read the library and set the clock period as 20 ns. Then, perform floorplanning and set the target utilization as 40%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 18 um,12 um, and the top-right corner as 43 um,42 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. After constructing power grids, perform IR drop analysis on M1 nodes of the power grids. And report the switching, leakage, internal, and total power of the design. In the routing stage, route the design from M1 to M7. In each stage, dump the def file and name it according to the stage." +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 40 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0.5) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a verilog-described netlist with a clk port called ""clk"", read the tech files and cell library information and set the clock period as 40 ns. Then, perform floorplanning and set the target utilization as 35%, and set the spacing between core and die as 12 microns. After that, place the pins on M8 and M9. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 30 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0.5 um, and the y-axis as0.5. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 5 and 5 um, and for the power rings on M8, set the width and spacing to 5 and 5 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"# Disconnect the nets of the instance 'input1' from the RC network + +# Get the design block +block = design.getBlock() + +# Find the instance with name 'input1' +inst = block.findInst('input1') + +# Get the pins of the instance +pins = inst.getITerms() + +# Iterate through the pins +for pin in pins: + # Get the net connected to the pin + net = pin.getNet() + if net: + # Set the RC disconnected flag for the net + net.setRCDisconnected(True) +",Disconnect the nets of the instance 'input1' from the RC network +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VSS_net = design.getBlock().findNet(""VSS"") +# Rip up the VSS grids +pdn_obj.ripUp(VSS_net)",Rip up the VSS grids +"from openroad import Tech, Design + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(118) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M6 and M7 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M6"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M7"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode)",How can I place I/O pins of the design block on M6 and M7 layers? +"from openroad import Tech, Design + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset()",How can I perform global placement? +"from openroad import Tech, Design + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Global Placement +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 30 times +gpl.setInitialPlaceMaxIter(30) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement +# In OpenROAD, global placement should be performed before macro placement +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Place the macros using the entire core area + core = design.getBlock().getCoreArea() + units = design.getBlock().getDbUnitsPerMicron() + core_lx = core.xMin() / units + core_ly = core.yMin() / units + core_ux = core.xMax() / units + core_uy = core.yMax() / units + design.getMacroPlacer().setFenceRegion(core_lx, core_ly, core_ux, core_uy) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl()",Place the macros onto the design block +"from openroad import Tech, Design + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)",Perform detailed placement in OpenROAD +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Add Filler Cells +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix)",Add filler cells on the design block +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power distribution network + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()",Show me how I can construct power distribution network in OpenROAD +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_spacing = [design.micronToDBU(5), design.micronToDBU(5)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(2) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for core +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top_pdn"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top_pdn"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +# Create power delivery network for macros +# Set the width of the PDN ring for macros and the spacing between VDD and VSS rings for macros +macro_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +macro_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +macro_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"" +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""Macro_core_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""Macro_core_grid_"" + str(i)) + for g in grid: + pdngen.makeRing(grid = g, layer0 = m5, width0 = macro_ring_width[0], spacing0 = macro_ring_spacing[0], + layer1 = m6, width1 = macro_ring_width[0], spacing1 = macro_ring_spacing[0], + starts_with = pdn.GRID, offset = macro_ring_core_offset, pad_offset = ring_pad_offset, extend = False, + pad_pin_layers = macro_ring_connect_to_pad_layers, nets = []) + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()",Show me how I can build power distribution network if my design has macros +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1""))",How can I perform IR drop analysis on the M1 layer where the pins are located? +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +design.evalTclString(""report_power"")","Report the switching power, internal power and leakage power of the design" +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Global Routing +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M6"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True)",Perform global routing in OpenROAD +"from openroad import Design, Tech +import openroad as ord + +tech = Tech() +# Read the files into Openroad +design = Design(tech) + +floorplan = design.getFloorplan() +# Set the floorplan utilization to 35% +floorplan_utilization = 35 +# Set the aspect ratio of the design (height/width) as 0.5 +floorplan_aspect_ratio = 0.5 +# Set the spacing between core and die as 12 +floorplan_core_spacing = [design.micronToDBU(12) for i in range(4)] +# Find the site in lef +db = ord.get_db() +libs = db.getLibs() +site_name = """" +for lib in libs: + sites = lib.getSites() + if len(sites) == 0: + continue + else: + site_name = sites[0].getName() + break +site = floorplan.findSite(site_name) +floorplan.initFloorplan(floorplan_utilization, floorplan_aspect_ratio, + floorplan_core_spacing[0], floorplan_core_spacing[1], + floorplan_core_spacing[2], floorplan_core_spacing[3], site) +floorplan.makeTracks()",How can I automatically search for the name of the site and use that for floorplanning? +"from openroad import Tech, Design +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +design.evalTclString(""create_clock -period 50 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"")","If the clock port is called clk_i, how can I set the design clock period to 50 nanoseconds?" +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name) + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk_i] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(45), design.micronToDBU(45)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(40), design.micronToDBU(40)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(5, 20, 5, 25) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMaxWl() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0) / site.getWidth()) +max_disp_y = int(design.micronToDBU(0) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +design.writeDef(""placement.def"") + +","Given a synthesized netlist with a clock port named ""clk_i"", read the library and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 45,45. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 40,40. After floorplanning, place the macros and the standard cells. Place the macros with a bounding box with the bottom-left corner as 5 um,5 um, and the top-right corner as 20 um,25 um. And place each macro at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 0 um, and the y-axis as0. After the placement stage, dump the def file and name it ""placement.def"". " +"from openroad import Tech, Design +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Clock Tree Synthesis +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.0435 -capacitance 0.0817"") +design.evalTclString(""set_wire_rc -signal -resistance 0.0435 -capacitance 0.0817"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X3"") +cts.setRootBuffer(""BUF_X3"") +cts.setSinkBuffer(""BUF_X3"") +cts.runTritonCts() + +# Detailed Placement +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(0.5) / site.getWidth()) +max_disp_y = int(design.micronToDBU(1) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)",Show me how I can perform CTS in OpenROAD +"from openroad import Tech, Design +import openroad as ord + +tech = Tech() +# Make sure you have files read into OpenROAD DB +design = Design(tech) +design.readDb(""xxx.odb"") + +# Detailed Routing +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M6"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main()",Perform detailed routing in OpenROAD +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +libFiles = libDir.glob(""*.lib"") +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +design = Design(tech)",How can I read .lib files into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Set file path +lefDir = Path(""lef_path"") +lefFiles = lefDir.glob('*.lef') +# Modify the technology file postfix for other naming convention +techLefFiles = lefDir.glob(""*.tech.lef"") +# Read library files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech)",How can I read .lef files into OpenROAD? +"from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path(""design_path"") +design_file_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" +verilogFile = designDir/str(design_file_name + "".v"") +design.readVerilog(""verilogFile"") +design.link(design_top_module_name)",Show me the way to read the Verilog file into OpenROAD +"from openroad import Design, Tech + +tech = Tech() +# Make sure to read all required files +design = Design(tech) +# Get PDNGen module +pdngen_obj = design.getPdnGen() +# Find the VDD net +VDD_net = design.getBlock().findNet(""VDD"") +# Rip up the VDD grids +pdngen_obj.ripUp(VDD_net)",Rip up the VDD grids +"import openroad as ord +from openroad import Tech, Design +import os, odb, drt, pdn, re +from pathlib import Path + +# Read Files + +tech = Tech() +# Set file path +libDir = Path(""lib_path"") +lefDir = Path(""lef_path"") +techlefDir = Path(""techlef_path"") +designDir = Path(""design_path"") + +design_name = ""design_filename"" +design_top_module_name = ""design_top_module_name"" + +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') +# Read library files +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) +design = Design(tech) +# Read design files +defFile = designDir/str(design_name + "".def"") +design.readDef(""defFile"") + +# Set the clocks +design.evalTclString(""create_clock -period 20 [get_ports clk] -name core_clock"") +design.evalTclString(""set_propagated_clock [all_clocks]"") +# Floorplanning + +floorplan = design.getFloorplan() +# Set the core and die area +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(40)) +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(35)) +# Find the site in lef +site = floorplan.findSite(""site_name"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks() + +# Place Pins + +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place the pins on M8 and M9 +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""M8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""M9"")) +IOPlacer_random_mode = True +design.getIOPlacer().run(IOPlacer_random_mode) + +# Global Placement + +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Set the max iteration of global placement to 10 times +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace() +gpl.doNesterovPlace() +gpl.reset() + +# Macro Placement + +macros = [inst for inst in ord.get_db_block().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + # Set the halo around macros to 5 microns + mpl_halo_x, mpl_halo_y = 5, 5 + mpl.setHalo(mpl_halo_x, mpl_halo_y) + # Set the channel width between macros to 5 microns + mpl_channel_x, mpl_channel_y = 5, 5 + mpl.setChannel(mpl_channel_x, mpl_channel_y) + # Set the fence region as a user defined area in microns + design.getMacroPlacer().setFenceRegion(30, 55, 15, 35) + # Snap the macro to layer M4 (usually M4) + layer = design.getTech().getDB().getTech().findLayer(""M4"") + mpl.setSnapLayer(layer) + mpl.placeMacrosCornerMinWL() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Clock Tree Synthesis + +design.evalTclString(""set_propagated_clock [core_clock]"") +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") + +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Can choose different buffer cells for cts +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Detailed Placement + +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False) + +# Add Filler Cells + +db = ord.get_db() +filler_masters = list() +# Filler cell prefix may be different when using different library +filler_cells_prefix = ""filler_.*"" +for lib in db.getLibs(): + for master in lib.getMasters(): + master_name = master.getConstName() + if re.fullmatch(filler_cells_prefix, master_name) != None: + filler_masters.append(master) +if len(filler_masters) == 0: + print(""wrong filler cell prefix"") +else: + design.getOpendp().fillerPlacement(filler_masters, filler_cells_prefix) + +# Power Planning + +# Global Connect +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDD$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDPE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VDDCE$"", net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSS$"", net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, instPattern = "".*"", + pinPattern = ""^VSSE$"", net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() +# Voltage Domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, switched_power = switched_power, + ground = VSS_net, secondary = secondary) +# Set the width of the PDN ring and the spacing between VDD and VSS rings +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +# When the two layers are parallel, specify the distance between via cuts. +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Define power grid for std cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, name = ""top"", starts_with = pdn.GROUND, + pin_layers = [], generate_obstructions = [], powercell = None, + powercontrol = None, powercontrolnetwork = ""STAR"") +m1 = design.getTech().getDB().getTech().findLayer(""M1"") +m4 = design.getTech().getDB().getTech().findLayer(""M4"") +m7 = design.getTech().getDB().getTech().findLayer(""M7"") +m8 = design.getTech().getDB().getTech().findLayer(""M8"") +grid = pdngen.findGrid(""top"") +for g in grid: + # Make Ring for the core + pdngen.makeRing(grid = g, layer0 = m7, width0 = core_ring_width[0], spacing0 = core_ring_spacing[0], + layer1 = m8, width1 = core_ring_width[0], spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, offset = core_ring_core_offset, pad_offset = core_ring_pad_offset, extend = False, + pad_pin_layers = ring_connect_to_pad_layers, nets = []) + # Add power and ground grid on M1 and attach to cell/macro's VDD/VSS pin + pdngen.makeFollowpin(grid = g, layer = m1, + width = design.micronToDBU(0.07), extend = pdn.CORE) + # Create the rest of the power delivery network + pdngen.makeStrap(grid = g, layer = m4, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m7, width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), pitch = design.micronToDBU(10.8), offset = design.micronToDBU(0), + number_of_straps = 0, snap = False, starts_with = pdn.GRID, extend = pdn.RINGS, nets = []) + pdngen.makeConnect(grid = g, layer0 = m1, layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m7, layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) +# Create power delivery network for macros +m5 = design.getTech().getDB().getTech().findLayer(""M5"") +m6 = design.getTech().getDB().getTech().findLayer(""M6"") +for i in range(len(macros)): + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, inst = macros[i], halo = halo, + pg_pins_to_boundary = True, default_grid = False, + generate_obstructions = [], is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + pdngen.makeStrap(grid = g, layer = m5, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeStrap(grid = g, layer = m6, width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), pitch = design.micronToDBU(6), offset = design.micronToDBU(0), + number_of_straps = 0, snap = True, starts_with = pdn.GRID, extend = pdn.CORE, nets = []) + pdngen.makeConnect(grid = g, layer0 = m4, layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m5, layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + pdngen.makeConnect(grid = g, layer0 = m6, layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], cut_pitch_y = pdn_cut_pitch[1], vias = [], techvias = [], + max_rows = 0, max_columns = 0, ongrid = [], split_cuts = dict(), dont_use_vias = ) + +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes() + +# Global Routing + +signal_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""M1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""M7"").getRoutingLevel() +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True) + +# Detailed Routing + +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""M1"" +params.topRoutingLayer = ""M7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main() + +# Static IR drop Analysis + +psm_obj = design.getPDNSim() +psm_obj.setNet(ord.Tech().getDB().getChip().getBlock().findNet(""VDD"")) +design.evalTclString(f""psm::set_corner [sta::cmd_corner]"") +psm_obj.analyzePowerGrid('', False, '', '') +drops = psm_obj.getIRDropForLayer(tech.getDB().getTech().findLayer(""M1"")) + +design.writeDef(""final.def"") + +","Given a placed design with a clk port called ""clk"", read the technology file and cell libraries, and set the clock period as 20 ns. Perform floorplan and set the bottom-left location of the bounding box of the die as 0,0 and the top-right corner as 60,40. Set the bottom-left corner of the core's bounding box as 5,5 and the top-right corner as 55,35. After floorplanning, place the macros and the standard cells. Set a fence region to place macros inside the bounding box with the bottom-left corner as 30 um,15 um, and the top-right corner as 55 um,35 um. Meanwhile ensure each macro is at least 5 um to each other, and set a halo region around each macro as 5 um. Set the iteration of the global router as 10 times. In the detailed placement stage, set the maximum displacement at the x-axis as 1 um, and the y-axis as3. After the placement stage, perform clock tree synthesis with using BUF_X2 as clock buffers, and set the unit resistance and the unit capacitance value for clock and signal wires to 0.03574 and 0.07516, respectively. Then construct a power grid with power rings on M7 and M8, and have power grids on M1 and M4 for standard cells and macros respectively. Set the width of the M1 grid as 0.07 um, and the width of the M4 grid is 1.2 um. Set the spacing of the M4 grid as 1.2 um and the pitch of the M4 power grid as 6 um. Set the width of the power grids on M7 to 1.4 um and set the spacing and the pitch to 1.4 um and 10.8 um. For the power rings on M7, set the width and spacing to 2 and 2 um, and for the power rings on M8, set the width and spacing to 2 and 2 um as well. If the design has macros, build power grids for macros on M5 and M6 , set the width and spacing of both M5 and M6 grids to 1.2 um, and set the pitch to 6 um. And if there are parallel grids, set the pitch of the via between two grids to 0 um. Last, set the offset to 0 for all cases. In the routing stage, route the design from M1 to M7. In the end, perform IR drop analysis on M1 and dump the def file and name it ""final.def""." +"def check_annealing_debug_and_print_config(): + # Get the IO Placer object of the design + io_placer = design.getIOPlacer() + + # Print the configurations of the IO placer + io_placer.printConfig() + + # Return whether the annealing debug is on + return io_placer.isAnnealingDebugOn() + +# Call the function to check the annealing debug mode and print the config +annealing_debug_on = check_annealing_debug_and_print_config()",Check if the annealing debug mode is on for the IO pin placer and print the configs of the IO pin placer +"# Get the defined top layer of the IO pin placer + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Return the top layer +topLayer = iop.getTopLayer()",Get the defined top layer of the IO pin placer +"def set_min_distance_if_zero(min_distance_value): + # Get the IO Placer object of the design + iop = design.getIOPlacer() + + # Get the parameters of the IO Placer + parameters = iop.getParameters() + + # Get the minimum distance + min_dist = parameters.getMinDistance() + + # Set the minimum distance to 100 if it is 0 + if min_dist == 0: + parameters.setMinDistance(min_distance_value) + + # Set min distance in tracks + parameters.setMinDistanceInTracks(True) + + return min_dist + +# Call the function with the hard-coded min distance value 100 +min_distance = set_min_distance_if_zero(100)",Get the minimum distance setting of the IO pin placer and set it to 100 if it is 0 +"# Get the number of DRVs, cloud size and set the could size to 500 from the detailed router + +# Get the Triton Route object of the design +triton_route = design.getTritonRoute() + +# Get the number of DRVs +num_drvs = triton_route.getNumDRVs() + +def get_and_set_drv_and_cloud_size(cloud_size_value): + # Get the Triton Route object of the design + triton_route = design.getTritonRoute() + + # Get the number of DRVs + num_drvs = triton_route.getNumDRVs() + + # Set the cloud size to the specified value + cloud_size = triton_route.setCloudSize(cloud_size_value) + + # Return the number of DRVs and cloud size + return (num_drvs, cloud_size) + +# Call the function with the hard-coded cloud size value of 500 +drv_and_cloud_size = get_and_set_drv_and_cloud_size(500) + +# Return the number of DRVs and cloud size +return (num_drvs, cloud_size)","Get the number of DRVs, cloud size and set the could size to 500 from the detailed router" +"# Change the setting of horizontal and vertical length of thr IO pin placer to 100 + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Set vertical and horizontal length to 100 +parameters.setVerticalLength(100) +parameters.setHorizontalLength(100)",Change the setting of horizontal and vertical length of thr IO pin placer to 100 +"# Adjust the setting of vertical length of the IO pin placer to 100 + +# Get the IO Placer object of the design +iop = design.getIOPlacer() + +# Get the parameters of the IO Placer +parameters = iop.getParameters() + +# Set vertical length to 100 +parameters.setVerticalLength(100)",Adjust the setting of vertical length of the IO pin placer to 100 \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.xlsx b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.xlsx new file mode 100644 index 0000000..f944253 Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/Flow_Dataset.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/README.md b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Prompt-Script/README.md @@ -0,0 +1 @@ + diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.csv b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.csv new file mode 100644 index 0000000..c5e7beb --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.csv @@ -0,0 +1,1008 @@ +Prompts,Answers +What is PDNGEN?,"The PDNGEN module (pdn) in OpenROAD aims to simplify the process of adding a power grid into a floorplan. A user can specify a small set of power grid policies to be applied to the design, such as the layers to use, stripe width, and spacing, and then pdn will generate the actual metal straps. Power grid policies can be defined over both the standard cell area and areas occupied by macros." +What does the -switch_cell argument in PDN do while doing power switch insertion?,"During power switch insertion, the -switch_cell argument is used to specify the name of a coarse-grain power switch cell that is to be inserted wherever the standard cell rail connects to the rest of the power grid. The mesh layers are associated with the unswitched power net of the voltage domain, whereas the standard cell rail is associated with the switched power net of the voltage domain. The placement of a power switch cell connects the unswitched power mesh to the switched power rail through a power switch defined by the define_power_switch_cell command." +What does the par module do?,"The partitioning module (par) is based on TritonPart, an open-source constraints-driven partitioner. par can be used to partition a hypergraph or a gate-level netlist. TritonPart solves multi-way partitioning by 1) constraints-driven coarsening, 2) initial partitioning, 3) refinement, 4) cut-overlay clustering and partitioning (COCP), and 5) V-cycle refinement. The purpose of partitioning a netlist is to reduce the complexity of a circuit so that algorithms can operate on smaller chunks of the netlist at a time. Partitioning a netlist may slightly reduce the optimization opportunities compared to a non-partitioned approach, but it greatly benefits the runtime. Partitioning a netlist may be the only option to feasibly operate on very large circuits." +Is TritonRoute the foundation of drt?,"The Detailed Routing (drt) module in OpenROAD is based on the open-source detailed router TritonRoute. TritonRoute consists of several main building blocks, including pin access analysis, track assignment, initial detailed routing, search and repair, and a DRC engine. The initial development of the router is inspired by the ISPD-2018 initial detailed routing contest. However, the current drt framework differs and is built from scratch, aiming for an industrial-oriented, scalable, and flexible flow." +What is the structure of OpenDB?,The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library-style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures. +How is FastRoute better than previous routing frameworks?,"FastRoute innovates over prior routing frameworks because it integrates several novel techniques: fast congestion-driven via-aware Steiner tree construction, 3-bend routing, virtual capacity adjustment, multi-source multi-sink maze routing, and spiral layer assignment. These techniques not only address the routing congestion measured at the edges of global routing grids but also minimize the total wirelength and via usage, which is critical for subsequent detailed routing, yield, and manufacturability. Experimental results show that FastRoute is highly effective and efficient in solving ISPD07 and ISPD08 global routing benchmark suites. The results outperform recently published academic global routers in both routability and runtime. In particular, for ISPD07 and ISPD08 global routing benchmarks, FastRoute generates 12 congestion-free solutions out of 16 benchmarks with a speed significantly faster than other routers." +What does RTLMP do?,"A macro placer (MP) is an algorithm which specifically focuses on placing macros in the core area. RTL­MP is a novel macro placer that utilizes RTL information and tries to “mimic” the interaction between the frontend RTL designer and the back­ end physical design engineer to produce human­-quality floorplans. By exploiting the logical hierarchy and processing logical modules based on connection signatures, RTL­MP can capture the dataflow inherent in the RTL and use the dataflow information to guide macro placement." +What was the need to develop Hier-RTLMP?,"Recently, with the increasing complexity of IP blocks, and in particular with auto-generated RTL for machine learning (ML) accelerators, the number of macros in a single RTL block can easily run into several hundred. This makes the task of generating an automatic floorplan (.def) with IO pin and macro placements for front-end physical synthesis even more critical and challenging. The so-called peripheral approach of forcing macros to the periphery of the layout is no longer viable when the ratio of the sum of the macro perimeters to the floorplan perimeter is large since this increases the required stacking depth of macros. Thus, a novel multilevel physical planning approach that exploits the hierarchy and dataflow inherent in the design RTL, and describes its realization in a new hierarchical macro placer, Hier-RTLMP was developed. " +How is Hier-RTLMP different from RTL-MP?,"Hier-RTLMP consists of an auto-clustering engine that transforms the logical hierarchy into a physical hierarchy. Unlike RTL-MP where the physical hierarchy is a single level, Hier-RTLMP’s autoclustering engine creates a multilevel physical hierarchy of physical clusters. This enables the handling of large RTLs with hundreds of macros and allows for the placement of macros within the core area." +How does FastRoute work?,"The first part of the FastRoute framework is topology generation. Because FastRoute tries to avoid rip-up and reroute to reduce both wirelength and runtime, the initial tree topology has significant impacts. With the congestion-driven and via-aware topology, the next stage of FastRoute is actual routing. We find that there exists significant potential to improve traditional routing techniques in terms of via control and congestion reduction. The most commonly used routing techniques in global routing include L/Z/U pattern routing, monotonic routing, and maze routing. In addition to new topology and routing techniques, Fast Route integrates several performance enhancement techniques to further improve routing quality and reduce run time." +Why is RSMT used more?,"Traditionally, global routing just uses tree structures like RMST or RSMT while RSMT is becoming more popular due to its minimal wirelength to connect a multi-pin net." +"Tab completion does work in console mode but not in GUI mode, why?","The OpenROAD GUI is made from custom Qt code and does not apply to the console. OpenROAD relies on the tclreadline package, which doesn't work well with imported namespaces." +"What do these Debug output mean? +[INFO MPL-0024] [Multilevel Autoclustering] Creating clustered netlist. +[INFO MPL-0039] [Coarse Shaping] Determining shape functions for clusters. +[INFO MPL-0028] [Hierarchical Macro Placement] Placing clusters and macros. +[INFO MPL-0037] Updated location of 95 macros +Delete buffers for RTLMP flow... +[INFO RSZ-0026] Removed 0 buffers.","Messages with the MPL prefix are from the macro placement (mpl) module. These messages are progress messages, informing the user which step of the HierRTLMP flow is being executed." +What are the units of the -pad_right and -pad_left arguments of the global_placement function,"In global_placement, -pad_right and -pad_left add padding which is measured in cell sites to effectively make the cell appear wider. pad_left adds a pad to the left side, pad_right adds it to the right side. Wider cells during global placement can help reduce placement congestion and make finding a valid placement easier." +Does space padding influence the design utilization? I feel like it shouldn't.,"Cell padding only impacts the way the global placer (gpl) and detailed placer (dpl) sees the cells. Cell padding does not change the logic area of the cell from the user perspective. If you were to use the report_design_area command, you would see the unpadded design utilization reported." +"Wouldn't manually adding pads in the global_placement function reduce the maximum design utilization possible for a design? Especially since OpenROAD wants to be automatic, GPL will stop everything if it sees a DU >100% even if it could achieve a reasonable DU with equivalent padding","Cell padding can reduce the maximum possible design utilization. If you don't want padding in your design, you can reduce the default padding or turn it off. However, padding is usually necessary to achieve a cleanly routed design, because cells which are too close together may make routing impossible. If you want to optimize for very high-density designs, I believe you can also set padding on a master-by-master basis so that only the most difficult cells are padded. This process may take some trial and error." +Why did I encounter an issue with CORE_UTILIZATION when trying to aim for a DU of 70% on the ASAP7 PDK which should be possible and reasonable for any design?,"If you are using ORFS, the CORE_UTILIZATION variable only determines the core utilization after Yosys (synthesis) runs using the netlist data. The utilization can change dramatically as OpenROAD performs timing optimization, which will insert buffers, remove buffers, and resize cells. For example, if you set CORE_UTILIZATION to 70% utilization during the initialization step, you may end up with 90%+ utilization because of optimization to meet timing constraints. It is currently up to the designer to ensure that the CORE_UTILIZATION is set appropriately, which may require some trial and error." +"If I have a design for which the detailed placement fails for a few instances, if I relax my timing constraints will it result in a successful placement?","Relaxing timing constraints can usually reduce your design utilization because fewer buffers will need to be inserted. However, detailed placement can fail for several reasons, including 1) setting core utilization too high, 2) not having enough cell padding during global placement, 3) having too much cell padding during detailed placement, 4) having a poor macro placement which will block placement of some standard cells" +"The timing optimizations done by the synthesis tool are ""discarded"" as the buffers are removed?","Empiracally, the OpenROAD team has found that OpenROAD optimizes better when the buffers from Yosys are removed, because Yosys does not do physical synthesis." +Is there no need to re-synthesize with different timing constraints with Yosys? Or does it also use different/bigger non-buffer cells that also need to be resized?,"Empirically, applying timing constraints to Yosys for synthesis does not have much impact on the output netlist. However, the results may not be identical if the timing constraints are changed." +"What does this warning mean? +[WARNING ODB-0208] VIA: duplicate VIA (via5_6_120_288_1_2_58_322) ignored...","This warning likely occurs because of multiple block abstracts with the same via. To fix this problem, one should ensure that the block abstracts do not have duplicates via definitions." +"Upon attempting to read an invalid ODB file, OpenROAD doesn't attempt to validate it and instead crashes with a cryptic message of Error: read_db.tcl, 1 ios_base::clear: unspecified iostream_category error. Why is this happening?","I would advise against using low-level OBD APIs to interact with OpenROAD. User-facing APIs in OpenROAD have documentation and error checking to prevent improper usage, however low-level APIs may not have error checking for performance reasons. In this case, it appears the db you are creating does not have a logger and can't issue any messages." +What is IR Drop Analysis?,"The IR Drop Analysis module in OpenROAD (psm) is based on PDNSim, an open-source static IR analyzer. PDNSim will perform a simulation based on the estimated current draw of each instance to estimate what is the voltage drop seen at each cell. That is, it shows the voltage drop between the voltage source(s) of the chip and each instance." +What are the features of IR Drop analysis?,"The features of IR Drope analysis are: reporting the worst IR drop, reporting the worst current density over all nodes and wire segments in the power distribution network (given a placed and PDN-synthesized design), checking for floating PDN stripes on the power and ground nets, and spice netlist writer for power distribution network wire segments." +What is Flute3?,Flute3 is an open-source rectilinear Steiner minimum tree heuristic with improvements made by UFRGS students and James Cherry. This tool is used for the calculation of wirelength in grt and rsz. +What is OpenDB?,"OpenDB is a design database to support tools for physical chip design. It was originally developed by Athena Design Systems. Nefelus, Inc. acquired the rights to the code and open-sourced it with BSD-3 license in 2019 to support the DARPA OpenROAD project. The structure of OpenDB is based on the text file formats LEF (library) and DEF (design) formats version 5.6. OpenDB supports a binary file format to save and load the design much faster than using LEF and DEF. OpenDB is written in C++ 98 with standard library style iterators. The classes are designed to be fast enough to base an application on without having to copy them into application-specific structures." +What is Automatic Code Generator used for?,The automatic code generator in OpenROAD is used to generate code for OpenDB objects and Iterators. It uses JSON input and automatically generates corresponding C++ files +What commands are used to read and write design data in OpenROAD?,"OpenROAD is run using Tcl scripts. The following commands are used to read and write design data. +read_lef [-tech] [-library] filename +read_def filename +write_def [-version 5.8|5.7|5.6|5.5|5.4|5.3] filename +read_verilog filename +write_verilog filename +read_db filename +write_db filename +write_abstract_lef filename" +"What support does OpenROAD have for Abstract LEF? +",OpenROAD contains an abstract LEF writer that can take your current design and emit an abstract LEF representing the external pins of your design and metal obstructions. Use the write_abstract_lef command to generate the abstract LEF. +What does the global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The global_connect command is used to define logical connections between supply pins on design instances and their respective supply nets. Note that the global_connect command only creates a logical connection; it does not perform any routing for a physical connection. +What does the clear_global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The clear_global_connect command is used to clear previously declared connections between supply pins on design instances and their respective supply nets. Note that the clear_global_connect command only clears the logical connections; it does not remove any routing or physical connections. +What does the report_global_connect command do?,Global connections are typically used to define connections between a supply net (such as power/ground) and the supply pins on cells. The report_global_connect command is used to print out the currently defined global connection rules. +What does the report_cell_usage command do?,The report_cell_usage command is used to print out the number of instances of each type of cell (master) used in the design. +How does OpenROAD compute the die area when using the core_utilization argument in the initialize_floorplan?,"To compute the die area for the initialize_floorplan command, OpenROAD first calculates the core area by dividing the total logic area of the instances coming from synthesis and by the specified core_utilization. OpenROAD then shapes that core area based on the aspect_ratio parameter. Finally, OpenROAD expands the core area by adding a core margin on each edge of the core area. Altogether, this forms the die area." +I would like to know if there is any way to write the log output from OpenROAD into a file (using a report_ type command)?,"To capture output from OpenROAD, you can use standard Unix file operations and redirections. OpenROAD outputs all messages directly to the stdout I/O stream." +What is the minimum number of metal layers OpenROAD can route in?,"OpenROAD has the theoretical ability to route as few as two layers, but it has rarely been tried by the developers due to the lack of a specialized channel router. It is expected that OpenROAD will hit some issues and have to iterate. If you try this and run into issues, please kindly file an issue on GitHub. However, if the PDK is proprietary, it will be more difficult for the OpenROAD team to diagnose and debug." +"Can OpenROAD work with multi-VT cells (HVT, LVT, SVT) and swap between them in a single run?","OpenROAD supports using multi-VT cell libraries, and it can swap between VT cells during optimization." +Can OpenROAD work with Multi-Mode-Multi-Corner Files (mmmc) ?,"OpenROAD supports multi-corner Static Timing Analysis (STA), but it doesn't currently support multi-mode STA. ""MMMC"" files from proprietary tools are stored in proprietary formats, which OpenROAD cannot support. The OpenSTA manual will contain more information about how to run multi-corner analysis." +Is SystemVerilog support limited to the constructs that Yosys supports?,The OpenROAD Flow is limited to the RTL language support that the Yosys synthesizer provides. Yosys currently provides support for a limited subset of SystemVerilog and full support for Verilog. OpenROAD only supports structural Verilog netlists. +What is the job of Pin Placer?,"Place pins on the boundary of the die on the track grid to minimize net wirelengths. Pin placement also creates a metal shape for each pin using min-area rules. For designs with unplaced cells, the net wirelength is computed considering the center of the die area as the unplaced cells' position." +What does Antenna Rule Checker do?,"This tool checks antenna violations and generates a report to indicate violated nets. See LEF/DEF 5.8 Language Reference, Appendix C, ""Calculating and Fixing Process Antenna Violations"" (p.389) for a description of antenna violations." +What is Clock Tree Synthesis in OpenROAD?,"Clock tree synthesis (CTS) is the step of distributing a clock to all endpoints (such as flip-flops) while trying to minimize power and skew (the different in clock arrival times between two registers). The clock tree synthesis module in OpenROAD (cts) is based on TritonCTS 2.0, and can be run using the clock_tree_synthesis command. TritonCTS 2.0 features on-the-fly characterization, and therefore does not need to pre-generate characterization data. The on-the-fly characterization feature can be optionally controlled by parameters specified by the configure_cts_characterization command. You can use the set_wire_rc command to set the clock routing layer used when calculating parasitics in this step." +Tell me about Detailed Placement in OpenROAD?,"The detailed placement module in OpenROAD (dpl) is based on OpenDP or Open-Source Detailed Placement Engine. Its key features are +fence region and fragmented ROWs." +Describe the Restructure module in OpenROAD?,The restructure module in OpenROAD (rmp) is based on an interface to ABC for local resynthesis. The package allows logic restructuring that targets area or timing. It extracts a cloud of logic using the OpenSTA timing engine and passes it to ABC through the blif interface. Multiple recipes for area or timing are run to obtain multiple structures from ABC; the most desirable among these is used to improve the netlist. The ABC output is read back by a blif reader which is integrated into OpenDB. Blif writer and reader also support constants from and to OpenDB. Reading back of constants requires insertion of tie cells which should be provided by the user as per the interface described below. +What is RePlAce in OpenROAD?,"RePlAce is a tool for advancing solution quality and routability validation in Global Placement. Its features are analytic and nonlinear placement algorithms. it solves electrostatic force equations using Nesterov's method, verified with various commercial technologies and research enablements using OpenDB, verified deterministic solution generation with various compilers and OS, and supports Mixed-size placement mode." +What is Hierarchical Macro Placement/ Hier-RTLMP?,"""Hier-RTLMP"" is defined as a hierarchical automatic macro placer for large-scale complex IP blocks. This tool builds on the existing RTLMP (mpl) framework, adopting a multilevel physical planning approach that exploits the hierarchy and data flow inherent in the design RTL." +Describe Parallax Static Timing Analyzer or OpenSTA?,"OpenSTA is a gate-level static timing verifier. As a stand-alone executable, it can be used to verify the timing of a design using standard file formats. OpenSTA uses a TCL command interpreter to read the design, specify timing constraints, and print timing reports." +What file formats are supported by Parallax Static Timing Analyzer or OpenSTA?,"The Following standard file formats are supported by Parallax Static Timing Analyzer or OpenSTA: Verilog netlist, Liberty library, SDC timing constraints,SDF delay annotation, and SPEF parasitics." +"`auto_place_pins pin_layer` places pins on a single layer but It should be able to place vertical pins (sides of the die) and horizontal pins (top and bottom of the die) in separate layers, why is it not able to do this?","I currently recommend using `io_placer` instead of `auto_place_pins`. Here's an example:```io_placer -hor_layer 3 -ver_layer 2```Note that `io_placer` uses cell placement information to guide the I/O pin placement. If placement has not yet been run, the `-random` flag is required, which will distribute the pins evenly over the die boundary." +What dependencies are required for TritonPart?,TritonPart in OpenROAD uses Google OR-Tools as the ILP solver. Please install Google OR-Tools. +What is DFT?,This tool is an implementation of Design For Testing. New nets and logic are added to allow IC designs to be tested for errors in manufacturing. Physical imperfections can cause hard failures and variability can cause timing errors. +Tell me about the parts of DFT insertion?,"A simple DFT insertion consists of the following parts: a scan_in pin where the test patterns are shifted in, a scan_out pin where the test patterns are read from, scan cells that replace flops with registers that allow for testing, one or more scan chains (shift registers created from your scan cells), a scan_enable pin to allow your design to enter and leave the test mode." +What is Read UPF Utility?,"This module contains functionality to read, and modify information from Unified Power Format (UPF) files." +What is Metal fill?,"Metal filling is a common process in integrated circuit design to enhance manufacturability and yield by making the density of metal shapes more uniform across the design. In OpenROAD, the Finale module (fin) inserts floating metal fill shapes to meet metal density design rules while obeying DRC constraints. The rules for generating metal fill shapes are driven by a JSON configuration file, and the schema can be found in the OpenROAD documentation." +Explain Chip-level Connections in OpenROAD?,"The chip-level connections module in OpenROAD (pad) is based on the open-source tool ICeWall. In this utility, either place an IO ring around the boundary of the chip and connect with either wirebond pads or a bump array." +Brief me on the parasitics extraction module?,"The parasitics extraction module in OpenROAD (rcx) is based on the open-source OpenRCX, a Parasitic Extraction (PEX, or RCX) tool that works on OpenDB design APIs. It extracts routed designs based on the LEF/DEF layout model. +OpenRCX extracts both Resistance and Capacitance for wires, based on coupling distance to the nearest wire and the track density context over and/or under the wire of interest, as well as cell abstracts. The capacitance and resistance measurements are based on equations of coupling distance interpolated on exact measurements from a calibration file, called the Extraction Rules file. The Extraction Rules file (RC technology file) is generated once for every process node and corner, using a provided utility for DEF wire pattern generation and regression modeling. +OpenRCX stores resistance, coupling capacitance, and ground (i.e., grounded) capacitance on OpenDB objects with direct pointers to the associated wire and via db objects. Optionally, OpenRCX can generate a .spef file." +What are the Gate Resizer commands?,The resizer commands stop when the design area is -max_utilization util percent of the core area. util is between 0 and 100. The resizer stops and reports an error if the maximum utilization is exceeded. +What is macro placement?,"The macro placement module in OpenROAD (mpl) is based on TritonMacroPlacer, an open-source ParquetFP-based macro cell placer. The macro placer places macros/blocks honoring halos, channels, and cell row ""snapping"". Run global_placement before macro placement." +What is global routing?,"The global routing module in OpenROAD (grt) is based on FastRoute, an open-source global router originally derived from Iowa State University's FastRoute4.1 algorithm. Global routing is responsible for creating routing guides for each net to simplify the job of the detailed router. The purpose of global routing is mainly to avoid overcongestion when creating the guides." +Elaborate on FastRoute?,"FastRoute is a global routing tool for VLSI back-end design. It is based on sequential rip-up and re-route (RRR) and a lot of novel techniques. FastRoute 1.0 first uses FLUTE to construct congestion-driven Steiner trees, which will later undergo the edge-shifting process to optimize tree structure to reduce congestion. It then uses pattern routing and maze routing with a logistic function-based cost function to solve the congestion problem. FastRoute 2.0 proposed monotonic routing and multi-source multi-sink maze routing techniques to enhance the capability to reduce congestion. FastRoute 3.0 introduced the virtual capacity technique to adaptively change the capacity associated with each global edge to divert wire usage from highly congested regions to less congested regions. FastRoute 4.0 proposed via-aware Steiner tree, 3-bend routing, and a delicate layer assignment algorithm to effectively reduce via count while maintaining outstanding congestion reduction capability. FastRoute 4.1 simplifies the way the virtual capacities are updated and applies a single set of tuning parameters to all benchmark circuits" +Brief me on OpenROAD Flow?,"OpenROAD-flow-scripts (ORFS) is a fully autonomous, RTL-GDSII flow for rapid architecture and design space exploration, early prediction of QoR, and detailed physical design implementation. However, ORFS also enables manual intervention for finer user control of individual flow stages through Tcl commands and Python APIs." +"I'm trying to port ORFS to a TSMC process. During the detailed route step, I get a lot of DRT-0073 errors. Utilization is set to 20% at the beginning of the P&R flow and it is a pretty simple design. Give me some tips about what to look into? +I have tried to run the pin_access command directly but the -verbose parameter does not seem to work as I don't get any more information","You can try the developer debugs to get a sense of what is going on. Put detailed_route_debug -pa -pa_markers -pin _3504_:A1 before you call detailed_route and run it in the GUI. It will stop at the pin and show you how it is trying to access it and any associated drc markers. You click the continue button to see the various steps. Hopefully, that gives you an idea as to what is going on. The other option is a support contract with precisioninno.com where we can help under NDA. +" +"Is there any way I can use just the RTL-MP2 stand-alone on either an RTL design or a gate netlist? The issue is, that we use proprietary tools so do not have an OpenDB database for our designs.","OpenROAD supports interoperability with other EDA tools through the industry standard Verilog, LEF, and DEF formats. In this case, you can import a DEF file into OpenROAD from an external tool, run RTL-MP2, and then export the DEF file. The DEF file format should be supported by nearly all EDA physical design tools." +How do I check DRC?,"In OpenROAD, you can use the check_drc command to run the design rule check (DRC). It should be noted that check_drc is not a general-purpose checker and only verifies signal routing according to routing rules from the technology LEF file. check_drc also requires routing guides in order to run, so global routing must be performed first. DRC is also commonly performed by an external tool which will check all layers, not just the metal routing layers." +What does the argument -floorplan_initialize do in read_def?,"When using the read_def command with the -floorplan_initialize argument, OpenROAD will read only physical placement information such as pin locations and instance locations. It does not read or redefine the netlist." +What does the argument -skip_pin_swap & -skip_gate_cloning do in repair_timing?,"These flags disable optimizations in case of trouble or unexpected results. They are mainly included as a failsafe for users, rather than something that is expected to be used." +What does the detailed_placement command do in OpenROAD?,"The detailed_placement command moves instances to legal locations after global placement. While the global placer (gpl) may place cells in a roughly optimal position, gpl may not place the cells in legal locations because they may not be aligned to cell rows or sites. The detailed placer (dpl) will legalize the cell by shifting it to a nearby location which is aligned to the cell site grid. The detailed_placement command only performs basic legalization and does not attempt to optimize placement. The optimize_mirroring and improve_placement commands will perform optimization on the legalized cells." +"What does the argument -max_displacement disp|{disp_x disp_y} do in detailed_placement +Command?","Max distance that an instance can be moved (in microns) when finding a site where it can be placed. Either set one value for both directions or set {disp_x disp_y} for individual directions. The default values are {0, 0}, and the allowed values within are integers [0, MAX_INT]. This argument is useful because it limits the amount of searching and therefore amount of runtime that the detailed placer can use." +What does the argument -disallow_one_site_gaps do in the detailed_placement command?,"detailed_place -disallow_one_site_gaps will disallow the detailed placer from leaving gaps between cells that are exactly one cell sitewide. This feature is mainly useful for PDKs that do not have filler cells which are one site-wide. In this case, one-site-wide gaps are unfillable and will cause DRC violations." +What does the argument -report_file_name do in the detailed_placement command?,"The -report_file_name argument for the detailed_placement command specifies where the report for detailed placement should be saved. The report is saved in the JSON format and contains metrics related to detailed_placement. If this argument is not provided, no report will be saved for the detailed_placement command." +What does the Set Placement Padding command do?,"The set_placement_padding command sets left and right padding in multiples of the row site width. Use the set_placement_padding command before legalizing placement to leave room for routing. Use the -global flag for padding that applies to all instances. Use -instances for instance-specific padding. The instances insts can be a list of instance names, or an instance object returned by the SDC get_cells command. To specify padding for all instances of a common master, use the -filter ""ref_name == "" option to get_cells." +What is the significance of the filler_placement command?,"The filler_placement command fills gaps between detail-placed instances to connect the power and ground rails in the rows. filler_masters is a list of master/macro names to use for filling the gaps. Wildcard matching is supported, so FILL* will match, e.g., FILLCELL_X1 FILLCELL_X16 FILLCELL_X2 FILLCELL_X32 FILLCELL_X4 FILLCELL_X8. To specify a different naming prefix from FILLER_ use -prefix ." +What is the purpose of the remove_fillers command?,This command removes all filler cells. +What does the check_placement command do?,The check_placement command checks the placement legality. It returns 0 if the placement is legal. +What does the argument -verbose in the check_placement command do?,The -verbose argument enables verbose logging in the check_placement command. +What does the argument -disallow_one_site_gaps in the check_placement command do?,The argument -disallow_one_site_gaps disables one site gap during placement check. +What role does this argument -report_file_name play in the check_placement command?,The argument -report_file_name in check_placement command files name for saving the report (e.g. report.json). +What does the optimize_mirroring command do?,The optimize_mirroring command mirrors instances about the Y axis in a weak attempt to reduce the total half-perimeter wirelength (HPWL). No arguments are needed for this function. +What are some useful developer commands in the detailed placement module in OpenROAD (dpl)?,"If you are a developer, you might find the following commands useful, 1. detailed_placement_debug: debug detailed placement. 2. get_masters_arg: get masters from a design. 3. get_inst_bbox: get the bounding box of an instance. 4. get_inst_grid_bbox: get the grid bounding box of an instance. 5. format_grid: format grid (takes in length x and site width w as inputs). 6. get_row_site: get row site name." +What does the argument [-max_length ] do in the set_dft_config command of DFT- Design For Testing?,The argument [-max_length ] takes an integer as input for setting the maximum number of bits that can be in each scan chain. +What does the argument [-clock_mixing] do in the set_dft_config command of DFT?,The argument [-clock_mixing] dictates how the architect mixes the scan flops based on the clock driver. The value no_mix creates scan chains with only one type of clock and edge. This may create unbalanced chains. The value clock_mix creates scan chains mixing clocks and edges. Falling edge flops are going to be stitched before the rising edge. +What does the report_dft_config command do in DFT- Design For Testing?,The report_dft_config command prints the current DFT configuration to be used by preview_dft and insert_dft. +What does the preview_dft command do in DFT- Design For Testing?,This command prints a preview of the scan chains that will be stitched by insert_dft. Use this command to iterate and try different DFT configurations. This command does not perform any modification to the design. +What does the argument [-verbose] do in the preview_dft command of DFT- Design For Testing?,The preview_dft command shows more information about each one of the scan chains that will be created. +What does the insert_dft command do in DFT- Design For Testing?,"The insert_dft command implements the scan chains into the design by performing the following actions: Scan Replace, Scan Architect, Scan Stitch. The result is a design with scan flops connected to form the scan chains." +Can you give me an example of a basic Design for Testing command?,Here is an example that will create scan chains with a max length of 10 bits mixing all the scan flops in the scan chains: set_dft_config -max_length 10 -clock_mixing clock_mix report_dft_config preview_dft -verbose insert_dft. +What are the limitations of Design for Testing (DFT)?,"The limitations of DFT-Design for Testing are as follows: there are no optimizations for the scan chains, this is a WIP, there is no way to specify existing scan ports to be used by scan insertion, there is currently no way to define a user-defined scan path, and can only work with one-bit cells." +What is the report_cts command in Clock Tree Synthesis (cst) in OpenROAD used for?,"It is used to extract metrics after a successful clock_tree_synthesis run. These metrics are the number of Clock Roots, number of Buffers Inserted, number of Clock Subnets, and number of Sinks." +What does the argument -out_file in report_cts command in Clock Tree Synthesis (cst) in OpenROAD do?,"The file to save cts reports. If this parameter is omitted, the report is streamed to stdout and not saved." +What does the clock_tree_synthesis_debug command in Clock Tree Synthesis (cst) in OpenROAD do?,This command is an option to plot the CTS to GUI. +Which environment is required for setting up OpenROAD flow scripts?,You can use the bash shell to run commands and scripts. +What are the ways of installing OpenROAD flow scripts/ ORFS?,"These are the ways of installing OpenROAD flow scripts/ ORFS: Docker, Pre-built Binaries, Windows Subsystem for Linux (WSL), and Local Installation." +What is the basic build command for OpenROAD flow scripts/ ORFS?,The basic basic build command in ORFS is ./build_openroad.sh --help. +What does the following argument do in the build command of ORFS: -o or —local?,"The argument, o or —local, builds locally instead of building a Docker image." +What operation does the -l or --latest argument perform in the build command of ORFS?,The -l or --latest argument specifies to use of the head of branch –or_branch or ‘master’ by default for tools/OpenROAD. +How is this argument utilized in the build command of ORFS: --or_branch BRANCH_NAME?,The -or_branch BRANCH_NAME argument stipulates the use of the head of branch BRANCH for tools/OpenROAD. +What role does this argument play in the build command of ORFS: --or_repo REPO_URL?, This argument enumerates to use of a fork at REPO-URL (https/ssh) for tools/OpenROAD. +What does the following argument do in the build command of ORFS: --no_init?,The --no_init argument prescribes skipping initializing submodules. +How does the following argument function in the build command of ORFS: -t N or --threads N?,The -t N or --threads N argument stipulates the use of N cpus when compiling software. +What is the purpose of the following argument in the build command of ORFS: -n or --nice?,"The -n or --nice flag in the build script instructs the build script to set all jobs to the maximim Unix ""niceness"". Niceness determines how much the operating system prefers to schedule process. The purpose of setting this flag is to ensure that a system is not overwhelmed by using all available processing primarily of the build jobs. The build will use all CPUs by default unless --threads is also given, then N threads are used instead." +What does the following argument do in the build command of ORFS: —yosys-args-overwrite?,This argument states to not use default flags set by this scrip during Yosys compilation. +What is the purpose of the following argument in the build command of ORFS: —yosys-args STRING?,The '—yosys-args STRING' argument adds additional compilation flags for Yosys compilation. +What function does the following argument serve in the build command of ORFS: —openroad-args-overwrite?,The '—openroad-args-overwrite' argument specifies to not use default flags set by this script during OpenROAD app compilation. +What does the following argument do in the build command of ORFS: —openroad-args STRING?,The '—openroad-args STRING' argument adds aditional compilation flags for OpenROAD app compilation. +What is the purpose of the following argument in the build command of ORFS: —lsoracle-enable?,This argument initiates compiling LSOracle since it is disabled by default as it is not currently used on the flow. +What does the following argument do in the build command of ORFS: —lsoracle-args-overwrite?,The '—lsoracle-args-overwrite' argument stipulates not to use default flags set by this script during LSOracle compilation. +What does the following argument achieve in the build command of ORFS: —lsoracle-args STRING?,This argument adds aditional compilation flags for LSOracle compilation. +What function does the following argument serve in the build command of ORFS: —install-path PATH?,The '—install-path PATH' delineates the path to install tools. Default is ${INSTALL_PATH}. +What does the following argument do in the build command of ORFS: —clean?,The '—clean' argument calls the git clean command interactively before compiling. It is useful to remove old build files. +What does the following argument do in the build command of ORFS: —clean-force?,This '—clean-force' argument will call git clean before compiling but WARNING: this option will not ask for confirmation. It is useful to remove old build files. +What function does the following argument serve in the build command of ORFS: -c or --copy-platforms?,This argument is only applicable to docker builds. It is used to copy platforms inside the docker image. +What does the following argument do in the build command of ORFS: —docker-args-overwrite?,The ' —docker-args-overwrite' argument is only applicable for docker builds. They specify to not use default flags set by this script for Docker builds. +What does the following argument do in the build command of ORFS: —docker-args STRING?,This argument is only applicable to docker builds. It is used to add additional compilation flags for the Docker build. +What is OpenROAD?,"The OpenROAD (""Foundations and Realization of Open, Accessible Design"") Project was launched in June 2018 within the DARPA IDEA program. OpenROAD aims to bring down the barriers of cost, expertise, and unpredictability that currently block designers' access to hardware implementation in advanced technologies. The project team is developing a fully autonomous, open-source toolchain for digital SoC layout generation, focusing on the RTL-to-GDSII phase of system-on-chip design. Thus, OpenROAD holistically attacks the multiple facets of today's design cost crisis: engineering resources, design tool licenses, project schedule, and risk." +What is AutoTuner?,"AutoTuner is a ""no-human-in-loop"" parameter tuning framework for commercial and academic RTL-to-GDS flows. AutoTuner provides a generic interface where users can define parameter configuration as JSON objects. This enables AutoTuner to easily support various tools and flows. AutoTuner also utilizes METRICS2.1 to capture PPA of individual search trials. With the abundant features of METRICS2.1, users can explore various reward functions that steer the flow autotuning to different PPA goals." +WHat are the current supported search algorithms by AutoTuner?,"AutoTuner contains top-level Python script for ORFS, each of which implements a different search algorithm. Current supported search algorithms are as follows: +Random/Grid Search, Population Based Training (PBT), Tree Parzen Estimator (HyperOpt), Bayesian + Multi-Armed Bandit (AxSearch), Tree Parzen Estimator + Covariance Matrix Adaptation Evolution Strategy (Optuna), Evolutionary Algorithm (Nevergrad)" +How to set the direction of tuning in AutoTuner?,"User-defined coefficient values (coeff_perform, coeff_power, coeff_area) of three objectives to set the direction of tuning are written in the script. Each coefficient is expressed as a global variable at the get_ppa function in PPAImprov class in the script (coeff_perform, coeff_power, coeff_area). Efforts to optimize each of the objectives are proportional to the specified coefficients." +What environment is required for AutoTuner?,"To set up AutoTuner, make sure you have a virtual environment set up with Python 3.9.X. There are plenty of ways to do this, we recommend using Miniconda, which is a free minimal installer for the package manager conda." +Which parameters/variables can be used for tune or sweep?,Any variable that can be set from the command line can be used for tune or sweep. +How to add verilog designs to ORFS repository for a full RTL-GDS flow execution?,The following design example is based on the design spm that implements a Single-port memory using gf180 platform. This procedure applies to any design for a given platform you choose. Start from the base directory OpenROAD-flow-scripts/flow. Step 1: Create the Verilog source files directory based on the top module name. Step 2: Create config.mk to define design configuration. Step 3: Define key design parameters in config.mk. Step 4: Define SDC constraints. Step 5: Add the design name to Makefile to run the flow with the make command. +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLATFORM?","While designing spm that implements a Single-port memory using gf180 platform, the export PLATFORM value can be gf180." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export DESIGN_NAME?","While designing spm that implements a Single-port memory using gf180 platform, the value of the parameter, export DESIGN_NAME can be spm." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export VERILOG_FILES?","For the value of export VERILOG_FILES parameter while designing spm that implements a Single-port memory using gf180 platform, it can be $(sort $(wildcard ./designs/src/$(DESIGN_NICKNAME)/*.v))" +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export SDC_FILE?","The parameter, export SDC_FILE can have the value ./designs/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc while designing spm that implements a Single-port memory using gf180 platform" +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export CORE_UTILIZATION?", The value of CORE_UTILIZATION may be subjective but one value for CORE_UTILIZATION while designing spm that implements a Single-port memory using gf180 platform40 +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export PLACE_DENSITY ","The value of the parameter, export PLACE_DENSITY while designing spm that implements a Single-port memory can be 0.6." +"While designing spm that implements a Single-port memory using gf180 platform, what can be the value of the following parameter, export TNS_END_PERCENT?","The value of the parameter, export TNS_END_PERCENT while designing spm that implements a Single-port memory can be 100." +What is the function of the Environment Variables for the OpenROAD Flow Scripts?,"Environment variables are used in the OpenROAD flow to define various platform, design, and tool-specific variables to allow finer control and user overrides at various flow stages. These are defined in the config.mk file located in the platform and design-specific directories." +"What does the general variables for all stages, SKIP_REPORT_METRICS do?","The SKIP_REPORT_METRICS general variable if set to 1, then metrics, report_metrics does nothing. This is useful to speed up builds." +"Can you explain the usage of the Library Setup variable, PROCESS?","The variable, PROCESS signifies a technology node or process in use." +"What is the function of the Library Setup variable, CORNER?",This CORNER variable specifies the Library to select based on corner BC/TC/WC. +"What is the description of Library Setup variable, TECH_LEF","This variable, TECH_LEF, stipulates a technology LEF file of the PDK that includes all relevant information regarding metal layers, vias, and spacing requirements." +"What is the description of Library Setup variable, SC_LEF",SC_LEF is used to specify the path to the technology standard cell LEF file. +"What is the function of the Library Setup variable, GDS_FILES",GDS_FILES specifies the path to platform GDS files. +"What is the description of Library Setup variable, LIB_FILES","LIB_FILES enumerates a Liberty file of the standard cell library with PVT characterization, input and output characteristics, timing, and power definitions for each cell." +"Can you explain the usage of the Library Setup variable, DONT_USE_CELLS?","In OpenROAD Flow Scripts, the DONT_USE_CELLS variable stores a list of cells to avoid when performing both synthesis and place & route. Basic wildcard patterns (*) are supported. You may want to mark a cell as dont_use for several reasons, including 1) some cells may have complicated pin access patterns which are more likely to cause design rule violations during detailed routing, 2) some cells may be more prone to manufacturing variation, and will cause difficulty to close timing constraints, 3) A designer may not want to use certain cells during the implementation flow." +"What does the following Synthesis variable, SYNTH_HIERARCHICAL do?","The variable SYNTH_HIERARCHICAL enables synthesis hierarchically, otherwise considered flat synthesis." +"What does the following Synthesis variable, LATCH_MAP_FILE do?",LATCH_MAP_FILE variable specifies the list of latches treated as a black box by Yosys. +"What does the following Synthesis variable, CLKGATE_MAP_FILE do?",This variable specifies a list of cells for the gating clock treated as a black box by Yosys. +"Can you explain the usage of this Synthesis variable, ADDER_MAP_FILE?",List of adders treated as a black box by Yosys. +"What does the following Synthesis variable, TIEHI_CELL_AND_PORT do?","The variable, TIEHI_CELL_AND_PORT is used to tie high cells used in Yosys synthesis to replace a logical 1 in the Netlist." +"What does the following Synthesis variable, TIELO_CELL_AND_PORT do?",This variable is used to tie low cells used in Yosys synthesis to replace a logical 0 in the Netlist. +"What does the following Synthesis variable, MIN_BUF_CELL_AND_PORTS do?",The MIN_BUF_CELL_AND_PORTS variable is used to insert a buffer cell to pass through wires. Used in synthesis. +"What does the following Synthesis variable, ABC_CLOCK_PERIOD_IN_PS do?","The variable, ABC_CLOCK_PERIOD_IN_PS is used to specify the clock period to be used by STA during synthesis. Default value read from constraint.sdc." +"What does the following Synthesis variable, ABC_DRIVER_CELL do?",Default driver cell used during ABC synthesis. +"What does the following Synthesis variable, ABC_LOAD_IN_FF do?","During synthesis, the set_load value specified by this, ABC_LOAD_IN_FF variable is used." +"What does the following Synthesis variable, MAX_UNGROUP_SIZE do?","For hierarchical synthesis, this variable ungroups modules of the size given by this variable." +"Tell me about the Floorplan variable, FLOORPLAN_DEF?",FLOORPLAN_DEF is used to specify the use of the DEF file to initialize floorplan. +"Elaborate on the Floorplan variable, PLACE_SITE?",Placement site for core cells defined in the technology LEF file. +"Describe the use this Floorplan variable, TAPCELL_TCL?",TAPCELL_TCL specifies the path to the Endcap and Welltie cells file. +"What is the function of the Floorplan variable, RTLMP_FLOW?","This variable, RTLMP_FLOW enables the Hierarchical RTLMP flow. By default it is disabled." +"Tell me about the Floorplan variable, MACRO_HALO?","MACRO_HALO specifies to keep out a distance from macro, in X and Y, to standard cell row." +"Tell me about the Floorplan variable, MACRO_PLACEMENT?",MACRO_PLACEMENT specifies the path of a file on how to place certain macros manually using read_macro_placement. +"Elaborate on the Floorplan variable, MACRO_PLACEMENT_TCL?",This variable specifies the path of a TCL file on how to place certain macros manually. +"Describe the Floorplan variable, MACRO_PLACE_HALO?",Horizontal /vertical halo around macros (microns). Used by automatic macro placement. +"Tell me about the Floorplan variable, MACRO_PLACE_CHANNEL?",Horizontal/vertical channel width between macros (microns). Used by automatic macro placement when RTLMP_FLOW is disabled. Imagine channel=10 and halo=5. Then macros must be 10 apart but standard cells must be 5 away from a macro. +"Give me details on the Floorplan variable, MACRO_BLOCKAGE_HALO?",Blockage width overridden from default calculation. +"Inform me about the Floorplan variable, PDN_TCL?","This variable specifies the file path which has a set of power grid policies used by pdn to be applied to the design, such as layers to use, stripe width and spacing to generate the actual metal straps." +"Tell me about the Floorplan variable, MAKE_TRACKS.",MAKE_TRACKS variable outlines the Tcl file that defines adding routing tracks to a floorplan. +"What is the function of the Floorplan variable, IO_PLACER_H?",The metal layer on which to place the I/O pins horizontally (top and bottom of the die). +"Inform me about the Floorplan variable, IO_PLACER_V?",The metal layer on which to place the I/O pins vertically (sides of the die). +"Tell me about the Floorplan variable, GUI_NO_TIMING?",Skip loading timing for a faster GUI load. +"Give me a description for the following ‘Placement’ tool variable, HAS_IO_CONSTRAINTS?",Skip the initial non-IO based global placement if IO constraints are present. +"Tell me about the ‘Placement’ tool variable, CELL_PAD_IN_SITES_GLOBAL_PLACEMENT?",Cell padding on both sides in site widths to ease routability during global placement. +"What does this ‘Placement’ tool variable, CELL_PAD_IN_SITES_DETAIL_PLACEMENT do?",Cell padding on both sides in site widths to ease routability in detail placement. +"Give me a description for the following ‘Placement’ tool variable, PLACE_DENSITY?",The desired placement density of cells. It reflects how spread the cells would be on the core area. 1.0 = closely dense. 0.0 = widely spread. +"What does this ‘Placement’ tool variable, PLACE_DENSITY_LB_ADDON do?",Check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists. +"State the function of this OpenROAD ‘Placement’ tool variable, REPAIR_PDN_VIA_LAYER?",Remove power grid vias which generate DRC violations after detailed routing. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GLOBAL_PLACEMENT_ARGS?",Use additional tuning parameters during global placement other than default args defined in gloabl_place.tcl. +"What does this OpenROAD ‘Placement’ tool variable, ENABLE_DPO do?",Enable detail placement with improve_placement feature. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, DPO_MAX_DISPLACEMENT?",Specifies how far an instance can be moved when optimizing. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_TIMING_DRIVEN?","In OpenROAD Flow Scripts (ORFS), the GPL_TIMING_DRIVEN variable specifies whether the global placer (gpl) should use timing driven-placement. Timing-driven placement will cause gpl to ocassionally run static timing analysis (sta) during placement in order to determine the timing on each net. gpl will then reweight the nets based on how timing-critical they are. This process improves the timing of the netlist by decreasing the distance between timing-critical cells, but it also causes an increase in gpl runtime due to running timing analysis." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, GPL_ROUTABILITY_DRIVEN?","In OpenROAD Flow Scripts (ORFS), the GPL_ROUTABILITY_DRIVEN variable specifies whether the global placer (gpl) should use routability driven-placement. Routability-driven placement will cause gpl to ocassionally run global routing (grt) during placement in order to determine routing congestion hotspots. gpl will then reweight the nets based on how congestion data. This process improves the routability of the netlist by spacing out cells in routing congested areas, but it also causes an increase in gpl runtime due to running global routing." +"Give me a description for the following OpenROAD ‘Placement’ tool variable, CAP_MARGIN?",Specifies a capacitance margin when fixing max capacitance violations. This option allow you to overfix. +"Give me a description for the following OpenROAD ‘Placement’ tool variable, SLEW_MARGIN?",Specifies a slew margin when fixing max slew violations. This option allow you to overfix. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, CTS_ARGS?",Override clock_tree_synthesis arguments +What does CTS_BUF_CELL do in ORFS?,The CTS_BUF_CELL variable sets the root buffer cell used in the clock tree during clock tree synthesis (CTS) +What is the use of the ORFS variable FILL_CELLS?,The FILL_CELLS variable holds a list of cell names to use as filler cells. Wildcard patterns (*) are supported. Fill cells are used to fill empty cell sites which aids in satisfying design rules and density rules. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, HOLD_SLACK_MARGIN?",Specifies a time margin for the slack when fixing hold violations. This option allow you to overfix. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SETUP_SLACK_MARGIN?",Specifies a time margin for the slack when fixing setup violations. +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_GATE_CLONING?",Do not use gate cloning transform to fix timing violations (default: use gate cloning) +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, SKIP_PIN_SWAP?",Do not use pin swapping as a transform to fix timing violations (default: use pin swapping) +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, TNS_END_PERCENT?","In OpenROAD Flow Scripts, the TNS_END_PERCENT variable specifies what percent of violating timing paths will be fixed during timing optimization. TNS_END_PERCENT must be a floating point value between 0-100. However, even if TNS_END_PERCENT is 0, the worst path will always be fixed. The purpose of this flag is to allow the user some control over how much runtime and logic area is spent on timing optimization, with a higher value leading to more runtime/area and a lower value leading to less runtime/area." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, EQUIVALENCE_CHECK?","In OpenROAD Flow Scripts, the EQUIVALENCE_CHECK variable toggles whether a logical equivalence check is run after timing optimization to ensure logical correctness of the circuit. If EQUIVALENCE_CHECK is 1, the check is performed. If EQUIVALENCE_CHECK is any other value or unset, the check is not run. The default value is unset." +"What is the use of the following OpenROAD Clock Tree Synthesis (CTS) variable, REMOVE_CELLS_FOR_EQY?","In OpenROAD Flow Scripts, the REMOVE_CELLS_FOR_EQY variable sets the list of cells to remove from the verilog netlist file produced specifically for netlist equivalence checking. Netlist equivalence checking is performed with the Yosys EQY tool. Wildcard patterns (*) are supported. This variable is passed directly to write_verilog -remove_cells <>." +What does the create_power_domain command do in upf?,This command creates power domain for a group of modules. +What does the create_logic_port command do in upf?,"This command creates logic port. Direction must be specified from: in, out, inout." +What does restructuring do?,"Restructuring (the rst module) uses logic resynthesis to optimize combinational logic paths. Restructuring can be performed in either area or delay mode. Area mode will optimize the logic cell area of the paths, whereas delay mode will optimize for delay. An Area Mode Example: restructure -liberty_file ckt.lib -target area -tielo_pin ABC -tiehi_pin DEF. For Timing Mode Example: restructure -liberty_file ckt.lib -target delay -tielo_pin ABC -tiehi_pin DEF -slack_threshold 1 -depth_threshold 2." +What is the difference between Yosys and OpenROAD?,Yosys is a logic synthesis tool which is responsible for transforming register transfer-level (RTL) code into a gate-level netlist. OpenROAD is a place and route (P&R) tool which is responsible for implementing a gale-level netlist into a chip layout. Yosys is developed by the YosysHQ organization whereas OpenROAD is developed by The OpenROAD Project. OpenROAD Flow Scripts (ORFS) makes use of both of these tools (as well as KLayout) to form a full RTL-to-GDS flow. +Is there a way of knowing which instances were modified by resize command ?,"The Resizer module (rsz) can modify the netlist by inserting or removing buffers, as well as increasing or decreasing the drive strength of cells. rsz does not save a log of which instances were modified, because it would create an excessively long log file. A recommended workaround solution would be to save a layout file (such as DEF or ODB) before performing resizing, and then compare it to a layout file after resizing." +How can I improve runtime?,"In OpenROAD, the runtime of the software is directly related to 1) the modeling accuracy and 2) the circuit optimization effort. Improving runtime is usually a tradeoff of one of these two categories. If you are comfortable with reducing optimization effort, such as when performing design space exploration, you could try the following techniques: 1) Relaxing timing constraints in the SDC file, 2) skipping unnesessary optimization routines, such as setup and hold time fixing, 3) Stopping the design flow early, such as after the placement step or clock tree synthesis (CTS) step." +Why does my design take so long?,"In OpenROAD, the runtime of the design can be affected by several factors: 1) the size of the netlist. Designs with a large number of instances (100k or more) can take significantly longer than small designs. 2) the physical area of the design. Designs with large die areas (~1 mm^2 or larger) can take longer because of having to store the die size in memory. 3) improper timing constraints. Designs with excessive timing constaints can cause optimization algorithms, particularly Resizer (rsz) to take excessively long. 4) host machine constraints. Large designs can require a large amount of RAM to run. If the required memory exceeds your machine's available memory, the runtime will be significantly increased. Additionally, OpenROAD scales well with core count, so using a CPU with a greater number of cores can improve runtime." +What is DBU?,"In OpenROAD, database units (DBU) are an integer representation of distance on a chip. In the LEF/DEF format, each technology specifies a conversion factor in terms of DBU/micron. For example, if a technology used a conversion factor of 2000 DBU/micron, that would mean that each DBU represents 0.0005 micron or 0.5 nm. The purpose for using DBU is that it enables faster calculation and no loss of precision compared to floating point representations." +How do I convert from DBU?,"In OpenROAD, an integer DBU value can be converted to a floating point micron value by using the ord::dbu_to_microns function" +How to access GUI,OpenROAD's GUI can be started in two ways. One is to use the -gui flag when invoking OpenROAD from the command line (e.g. openroad -gui). The other option is to use the gui::show function from inside the openroad command interpreter. +Is there a simple way to open the GUI in ORFS?,"OpenROAD Flow Scripts (ORFS) includes Makefile targets to open the GUI after each step. You can use the command make gui_*, where * is the name of the flow step (e.g. make_floorplan)." +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, \ No newline at end of file diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.xlsx b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.xlsx new file mode 100644 index 0000000..5c88adc Binary files /dev/null and b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/Question-Answer_Dataset.xlsx differ diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/README.md b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/Question-Answer/README.md @@ -0,0 +1 @@ + diff --git a/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/README.md b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/Non-Augmented_Data/README.md @@ -0,0 +1 @@ + diff --git a/flow-Agent/EDA-Corpus-main/README.md b/flow-Agent/EDA-Corpus-main/README.md new file mode 100644 index 0000000..a08f7bc --- /dev/null +++ b/flow-Agent/EDA-Corpus-main/README.md @@ -0,0 +1,108 @@ +# EDA Corpus +EDA Corpus is a data corpus for Electronic Design Automation (EDA) Large Language Model (LLM) research. In particular, the datapoints are tailored to [OpenROAD](https://github.com/The-OpenROAD-Project/OpenROAD) and [OpenROAD-flow-scripts](https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts). The corpus contains datasets for both question-answering and prompt-scripting for OpenROAD to improve user productivity. + +## Background +Recent works have shown that LLMs have tremendous potential in the chip design area in terms of writing code/script for hardware description language (HDL) or electronic design automation (EDA) flow. However, many of these works rely on data which are not publicly available and/or not permissively licensed for use in LLM training and distribution, especially in the EDA domain. To foster research in LLM-assisted physical design, we introduce EDA Corpus, a curated dataset for physical design automation tasks. EDA Corpus is based on OpenROAD, a widely utilized open-source EDA tool for automated place and route tasks. Leveraging OpenROAD mitigates obstacles associated with proprietary EDA tools, enabling the public release of our dataset and facilitating its use with LLMs without licensing constraints. + +## Dataset Description +EDA Corpus consists of two types of data: (1) question-answer (QA) pairs and (2) prompt-script (PS) pairs + +| **Dataset** | **Description** | **Non-augmented** | **Augmented**\* | +|--------------------|-----------------|-------------------|-----------------| +| `eda-corpus-qa-v1` | Question-answer | 198 data pairs | 590 data pairs | +| `eda-corpus-ps-v1` | Prompt-script | 395 data pairs | 943 data pairs | +| `eda-corpus-v1` | Combined QA/PS | 593 data pairs | 1533 data pairs | + +\* The augmented dataset is a superset of non-augmented + +### Question-answer (QA) dataset + - Contains pairs of question prompts and prose answers which are collected from The OpenROAD Project's GitHub issues, discussions, and documentation + - Datapoints are categorized into three categories: OpenROAD general, OpenROAD tool, and OpenROAD flow + - CSV file format and Microsoft Excel file format provided + +An example question-answer pair: +**Question:** + +***What does the SKIP_PIN_SWAP variable in Clock Tree Synthesis indicate?*** + +**Answer:** + +***Do not use pin swapping as a transform to fix timing violations (default: use pin swapping)*** + +#### Augmentation +The augmented dataset includes data pairs formed through paraphrasing questions and answers in order to enhance semantic diversity. + +### Prompt-script (PS) dataset + - Contains pairs of scripting prompts and OpenROAD Python scripts + - Data points are categorized into two three categories: flow scripts and database (DB) scripts + - CSV file format and Microsoft Excel file format provided + +While Tcl is the normal interface for OpenROAD, leveraging Python allows the reuse of pretrained LLMs for Python code generation. It is worth noting that Python code examples are significantly more prevalent, hence the focus on Python-based scripts. + +An example prompt-script pair: +**Prompt:** + +***Show me how I can read a Verilog file into OpenROAD.*** + +**Script:** + +#### Augmentation +While each augmented datapoint is distinct, the augmented points may perform similar functions with script parameter variations. For instance, the augmented set has a few instances of gate sizing, and the sizing is different between datapoints. The data is augmented through two methods: + +1. **Paraphrasing prompts**: prompts are paraphrased to increase semantic diversity. +2. **Variable and parameter changes**: pairs are duplicated with changes to the prompt parameters and script variable names. + +```python +from openroad import Tech, Design +from pathlib import Path + +tech = Tech() +# Make sure you have .lef files read into OpenROAD DB +design = Design(tech) + +designDir = Path("design_path") +design_file_name = "design_filename" +design_top_module_name = "design_top_module_name" +verilogFile = designDir/str(design_file_name + ".v") +design.readVerilog("verilogFile") +design.link(design_top_module_name) +``` + +# Citing This Work + +If you use this corpus in your work, please use the following citation: +``` +@inproceedingsV{wu2024eda, + title = {EDA Corpus: A Large Language Model Dataset for Enhanced Interaction with OpenROAD}, + author = {Wu, Bing-Yue and Sharma, Utsav and Kankipati, Sai Rahul Dhanvi and Yadav, Ajay and George, Bintu Kappil and Guntupalli, Sai Ritish and Rovinski, Austin and Chhabria, Vidya A.}, + booktitle = {The First IEEE International Workshop on LLM-Aided Design (LAD'24)}, + month = {June}, + year = {2024}, + organization = {IEEE}, + address = {New York, NY} +} +``` + +## Taxonomy +The question-answer and prompt-script data should be individually referred to as "datasets". The two dataset combined should be referred to as a "corpus". + +Citations to this work can be mentioned by `corpusName-datasetName-version`: + +| **Data** | **Name** | +|------------------------------|--------------------| +| All of EDA Corpus | `eda-corpus-v1` | +| Only question-answer dataset | `eda-corpus-qa-v1` | +| Only prompt-script dataset | `eda-corpus-ps-v1` | + +Additionally, you can mention whether you use the **augmented** or **non-augmented** versions. For example, "We train on the augmented eda-corpus-ps-v1 dataset." + +## License +[![CC BY 4.0][cc-by-shield]][cc-by] + +EDA Corpus is licensed under a [Creative Commons Attribution 4.0 International License][cc-by]. If you use EDA Corpus in a published scholarly work, please use the above citation. If you use EDA Corpus in another publication such as an article or blog post, please include a link to this repository. + +[![CC BY 4.0][cc-by-image]][cc-by] + +[cc-by]: http://creativecommons.org/licenses/by/4.0/ +[cc-by-image]: https://i.creativecommons.org/l/by/4.0/88x31.png +[cc-by-shield]: https://img.shields.io/badge/License-CC%20BY%204.0-lightgrey.svg diff --git a/flow-Agent/Makefile b/flow-Agent/Makefile index c22726e..dc4ab69 100644 --- a/flow-Agent/Makefile +++ b/flow-Agent/Makefile @@ -2,31 +2,27 @@ # file to avoid having to adding the to the make command line. -include settings.mk INT_PARAM=1 +# PYTHON_EXE ?= $(shell command -v python3 || command -v python) # ============================================================================== # Uncomment or add the design to run # ============================================================================== -DESIGN_CONFIG=./designs/sky130hd/aes/config_$(INT_PARAM).mk +#DESIGN_CONFIG=./designs/sky130hd/aes/config_$(INT_PARAM).mk #DESIGN_CONFIG=./designs/sky130hd/ibex/config_$(INT_PARAM).mk #DESIGN_CONFIG=./designs/sky130hd/jpeg/config_$(INT_PARAM).mk -#DESIGN_CONFIG=./designs/asap7/aes/config_$(INT_PARAM).mk +DESIGN_CONFIG=./designs/asap7/aes/config_$(INT_PARAM).mk #DESIGN_CONFIG=./designs/asap7/ibex/config_$(INT_PARAM).mk #DESIGN_CONFIG=./designs/asap7/jpeg/config_$(INT_PARAM).mk - - +$(info Using config.mk from $(DESIGN_CONFIG)) # Default design # DESIGN_CONFIG ?= ./designs/nangate45/gcd/config.mk # Include design and platform configuration before setting default options # in this file. This allows the DESIGN_CONFIG to set different defaults than # this file. -include $(DESIGN_CONFIG) -# If we are running headless use offscreen rendering for save_image -ifeq ($(DISPLAY),) -export QT_QPA_PLATFORM ?= offscreen -endif +include $(DESIGN_CONFIG) # ============================================================================== # ____ _____ _____ _ _ ____ @@ -43,7 +39,7 @@ MAKEFLAGS += --no-builtin-rules #------------------------------------------------------------------------------- # Default target when invoking without specific target. -.DEFAULT_GOAL := finish +.DEFAULT_GOAL := all #------------------------------------------------------------------------------- # Proper way to initiate SHELL for make @@ -56,16 +52,10 @@ SHELL := /usr/bin/env bash # location # - default is current install / clone directory ifeq ($(origin FLOW_HOME), undefined) -FLOW_HOME := $(shell pwd) + FLOW_HOME := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))) endif export FLOW_HOME -#------------------------------------------------------------------------------- -# Setup variables to point to other location for the following sub directory -# - designs - default is under current directory -# - platforms - default is under current directory -# - work home - default is current directory -# - utils, scripts, test - default is under current directory export DESIGN_HOME ?= $(FLOW_HOME)/designs export PLATFORM_HOME ?= $(FLOW_HOME)/platforms export WORK_HOME ?= . @@ -74,170 +64,46 @@ export UTILS_DIR ?= $(FLOW_HOME)/util export SCRIPTS_DIR ?= $(FLOW_HOME)/scripts export TEST_DIR ?= $(FLOW_HOME)/test -$(foreach line,$(shell $(SCRIPTS_DIR)/defaults.py),$(eval export $(line))) - -PUBLIC=nangate45 sky130hd sky130hs asap7 ihp-sg13g2 gf180 - -ifneq ($(wildcard $(PLATFORM_HOME)/$(PLATFORM)),) - export PLATFORM_DIR = $(PLATFORM_HOME)/$(PLATFORM) -else ifneq ($(findstring $(PLATFORM),$(PUBLIC)),) - export PLATFORM_DIR = ./platforms/$(PLATFORM) -else ifneq ($(wildcard ../../$(PLATFORM)),) - export PLATFORM_DIR = ../../$(PLATFORM) -else - $(error [ERROR][FLOW] Platform '$(PLATFORM)' not found.) -endif - -include $(PLATFORM_DIR)/config.mk - -# Enables hierarchical yosys -export SYNTH_HIERARCHICAL ?= 0 -export SYNTH_STOP_MODULE_SCRIPT = $(RESULTS_DIR)/keep_hierarchy.tcl -export HIER_REPORT_SCRIPT = $(SCRIPTS_DIR)/synth_hier_report.tcl -export MAX_UNGROUP_SIZE ?= 0 +export FLOW_VARIANT ?=base -# Enables Re-synthesis for area reclaim -export RESYNTH_AREA_RECOVER ?= 0 -export RESYNTH_TIMING_RECOVER ?= 0 -export ABC_AREA ?= 0 +include $(FLOW_HOME)/scripts/variables.mk -# User adjustable synthesis arguments -export SYNTH_ARGS ?= -flatten -# Not normally adjusted by user -export SYNTH_OPERATIONS_ARGS ?= -extra-map $(FLOW_HOME)/platforms/common/lcu_kogge_stone.v -export SYNTH_FULL_ARGS ?= $(SYNTH_ARGS) $(SYNTH_OPERATIONS_ARGS) - -# Global setting for Floorplan -export PLACE_PINS_ARGS - -export FLOW_VARIANT ?= base - -export GPL_TIMING_DRIVEN ?= 1 -export GPL_ROUTABILITY_DRIVEN ?= 1 - -# Cell padding in SITE widths to ease rout-ability. Applied to both sides -export CELL_PAD_IN_SITES_GLOBAL_PLACEMENT ?= 0 -export CELL_PAD_IN_SITES_DETAIL_PLACEMENT ?= 0 - -export ENABLE_DPO ?= 1 -export DPO_MAX_DISPLACEMENT ?= 5 1 - -# Setup working directories export DESIGN_NICKNAME ?= $(DESIGN_NAME) - export DESIGN_CONFIG + export DESIGN_DIR = $(dir $(DESIGN_CONFIG)) export LOG_DIR = $(WORK_HOME)/logs/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)_$(INT_PARAM) export OBJECTS_DIR = $(WORK_HOME)/objects/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)_$(INT_PARAM) export REPORTS_DIR = $(WORK_HOME)/reports/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)_$(INT_PARAM) export RESULTS_DIR = $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)_$(INT_PARAM) +# default value "base" for FLOW_VARIANT and "." for WORK_HOME are duplicated +# from variables.yaml and variables.mk because we need it +# earlier in the flow for BLOCKS. BLOCKS is a feature specific to the +# ORFS Makefile. + +# BLOCKS is a ORFS make flow specific feature. ifneq ($(BLOCKS),) - $(foreach block,$(BLOCKS),$(eval BLOCK_LEFS += ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef)) - $(foreach block,$(BLOCKS),$(eval BLOCK_LIBS += ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lib)) - $(foreach block,$(BLOCKS),$(eval BLOCK_GDS += ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.gds)) - $(foreach block,$(BLOCKS),$(eval BLOCK_CDL += ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.cdl)) - $(foreach block,$(BLOCKS),$(eval BLOCK_LOG_FOLDERS += ./logs/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/)) + # Normally this comes from variables.yaml, but we need it here to set up these variables + # which are part of the DESIGN_CONFIG. BLOCKS is a Makefile specific concept. + $(foreach block,$(BLOCKS),$(eval BLOCK_LEFS += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef)) + $(foreach block,$(BLOCKS),$(eval BLOCK_TYP_LIBS += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}_typ.lib)) + $(foreach block,$(BLOCKS),$(eval BLOCK_FAST_LIBS += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}_fast.lib)) + $(foreach block,$(BLOCKS),$(eval BLOCK_SLOW_LIBS += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}_slow.lib)) + $(foreach block,$(BLOCKS),$(eval BLOCK_GDS += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.gds)) + $(foreach block,$(BLOCKS),$(eval BLOCK_CDL += $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.cdl)) + $(foreach block,$(BLOCKS),$(eval BLOCK_LOG_FOLDERS += $(WORK_HOME)/logs/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/)) export ADDITIONAL_LEFS += $(BLOCK_LEFS) - export ADDITIONAL_LIBS += $(BLOCK_LIBS) + export ADDITIONAL_LIBS += $(BLOCK_TYP_LIBS) + export ADDITIONAL_TYP_LIBS += $(BLOCK_TYP_LIBS) + export ADDITIONAL_FAST_LIBS += $(BLOCK_FAST_LIBS) + export ADDITIONAL_SLOW_LIBS += $(BLOCK_SLOW_LIBS) export ADDITIONAL_GDS += $(BLOCK_GDS) - export GDS_FILES += $(BLOCK_GDS) ifneq ($(CDL_FILES),) export CDL_FILES += $(BLOCK_CDL) endif endif -export RTLMP_FLOW ?= 1 -export RTLMP_RPT_DIR ?= $(OBJECTS_DIR)/rtlmp -export RTLMP_RPT_FILE ?= partition.txt -export RTLMP_BLOCKAGE_FILE ?= $(OBJECTS_DIR)/rtlmp/partition.txt.blockage - -#------------------------------------------------------------------------------- -ifeq (,$(strip $(NUM_CORES))) - # Linux (utility program) - NUM_CORES := $(shell nproc 2>/dev/null) - - ifeq (,$(strip $(NUM_CORES))) - # Linux (generic) - NUM_CORES := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) - endif - ifeq (,$(strip $(NUM_CORES))) - # BSD (at least FreeBSD and Mac OSX) - NUM_CORES := $(shell sysctl -n hw.ncpu 2>/dev/null) - endif - ifeq (,$(strip $(NUM_CORES))) - # Fallback - NUM_CORES := 1 - endif -endif -export NUM_CORES - -YOSYS_FLAGS += -v 3 - -#------------------------------------------------------------------------------- -# setup all commands used within this flow -export TIME_BIN ?= /usr/bin/time -TIME_CMD = $(TIME_BIN) -f 'Elapsed time: %E[h:]min:sec. CPU time: user %U sys %S (%P). Peak memory: %MKB.' -TIME_TEST = $(shell $(TIME_CMD) echo foo 2>/dev/null) -ifeq (,$(strip $(TIME_TEST))) - TIME_CMD = $(TIME_BIN) -endif - -# The following determine the executable location for each tool used by this flow. -# Priority is given to -# 1 user explicit set with variable in Makefile or command line, for instance setting OPENROAD_EXE -# 2 ORFS compiled tools: openroad, yosys -export OPENROAD_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/openroad) -export OPENSTA_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/sta) - -OPENROAD_ARGS = -no_init -threads $(NUM_CORES) $(OR_ARGS) -OPENROAD_CMD = $(OPENROAD_EXE) -exit $(OPENROAD_ARGS) -OPENROAD_NO_EXIT_CMD = $(OPENROAD_EXE) $(OPENROAD_ARGS) -OPENROAD_GUI_CMD = $(OPENROAD_EXE) -gui $(OR_ARGS) - -YOSYS_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/yosys/bin/yosys) - -# Use locally installed and built klayout if it exists, otherwise use klayout in path -KLAYOUT_DIR = $(abspath $(FLOW_HOME)/../tools/install/klayout/) -KLAYOUT_BIN_FROM_DIR = $(KLAYOUT_DIR)/klayout - -ifeq ($(wildcard $(KLAYOUT_BIN_FROM_DIR)), $(KLAYOUT_BIN_FROM_DIR)) -KLAYOUT_CMD ?= sh -c 'LD_LIBRARY_PATH=$(dir $(KLAYOUT_BIN_FROM_DIR)) $$0 "$$@"' $(KLAYOUT_BIN_FROM_DIR) -else -ifeq ($(KLAYOUT_CMD),) -KLAYOUT_CMD := $(shell command -v klayout) -endif -endif -KLAYOUT_FOUND = $(if $(KLAYOUT_CMD),,$(error KLayout not found in PATH)) - -ifneq ($(shell command -v stdbuf),) - STDBUF_CMD ?= stdbuf -o L -endif - -#------------------------------------------------------------------------------- -WRAPPED_LEFS = $(foreach lef,$(notdir $(WRAP_LEFS)),$(OBJECTS_DIR)/lef/$(lef:.lef=_mod.lef)) -WRAPPED_LIBS = $(foreach lib,$(notdir $(WRAP_LIBS)),$(OBJECTS_DIR)/$(lib:.lib=_mod.lib)) -export ADDITIONAL_LEFS += $(WRAPPED_LEFS) $(WRAP_LEFS) -export LIB_FILES += $(WRAP_LIBS) $(WRAPPED_LIBS) - -export DONT_USE_LIBS = $(patsubst %.lib.gz, %.lib, $(addprefix $(OBJECTS_DIR)/lib/, $(notdir $(LIB_FILES)))) -export DONT_USE_SC_LIB ?= $(firstword $(DONT_USE_LIBS)) - -# Stream system used for final result (GDS is default): GDS, GSDII, GDS2, OASIS, or OAS -STREAM_SYSTEM ?= GDS -ifneq ($(findstring GDS,$(shell echo $(STREAM_SYSTEM) | tr '[:lower:]' '[:upper:]')),) - export STREAM_SYSTEM_EXT := gds - GDSOAS_FILES = $(GDS_FILES) - ADDITIONAL_GDSOAS = $(ADDITIONAL_GDS) - SEAL_GDSOAS = $(SEAL_GDS) -else - export STREAM_SYSTEM_EXT := oas - GDSOAS_FILES = $(OAS_FILES) - ADDITIONAL_GDSOAS = $(ADDITIONAL_OAS) - SEAL_GDSOAS = $(SEAL_OAS) -endif -export WRAPPED_GDSOAS = $(foreach lef,$(notdir $(WRAP_LEFS)),$(OBJECTS_DIR)/$(lef:.lef=_mod.$(STREAM_SYSTEM_EXT))) - define GENERATE_ABSTRACT_RULE ifeq ($(wildcard $(3)),) # There is no unique config.mk for this module, use the shared @@ -260,40 +126,10 @@ endef # Targets to harden Blocks in case of hierarchical flow is triggered .PHONY: build_macros -build_macros: $(BLOCK_LEFS) $(BLOCK_LIBS) - -$(foreach block,$(BLOCKS),$(eval $(call GENERATE_ABSTRACT_RULE,./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef,./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lib,$(shell dirname $(DESIGN_CONFIG))/${block}/config.mk))) -$(foreach block,$(BLOCKS),$(eval ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.gds: ./results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef)) - -# Utility to print tool version information -#------------------------------------------------------------------------------- -.PHONY: versions.txt -versions.txt: - mkdir -p $(OBJECTS_DIR) - @if [ -z "$(YOSYS_EXE)" ]; then \ - echo >> $(OBJECTS_DIR)/$@ "yosys not installed"; \ - else \ - $(YOSYS_EXE) -V > $(OBJECTS_DIR)/$@; \ - fi - @echo openroad `$(OPENROAD_EXE) -version` >> $(OBJECTS_DIR)/$@ - @if [ -z "$(KLAYOUT_CMD)" ]; then \ - echo >> $(OBJECTS_DIR)/$@ "klayout not installed"; \ - else \ - $(KLAYOUT_CMD) -zz -v >> $(OBJECTS_DIR)/$@; \ - fi - -# Pre-process libraries -# ============================================================================== - -# Create temporary Liberty files which have the proper dont_use properties set -# For use with Yosys and ABC -.SECONDEXPANSION: -$(DONT_USE_LIBS): $$(filter %$$(@F) %$$(@F).gz,$(LIB_FILES)) - @mkdir -p $(OBJECTS_DIR)/lib - $(UTILS_DIR)/preprocessLib.py -i $^ -o $@ +build_macros: $(BLOCK_LEFS) $(BLOCK_TYP_LIBS) -$(OBJECTS_DIR)/lib/merged.lib: - $(UTILS_DIR)/mergeLib.pl $(PLATFORM)_merged $(DONT_USE_LIBS) > $@ +$(foreach block,$(BLOCKS),$(eval $(call GENERATE_ABSTRACT_RULE,$(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef,$(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}_typ.lib,$(shell dirname $(DESIGN_CONFIG))/${block}/config.mk))) +$(foreach block,$(BLOCKS),$(eval $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/6_final.gds: $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)_$(block)/$(FLOW_VARIANT)/${block}.lef)) # Pre-process KLayout tech # ============================================================================== @@ -305,25 +141,13 @@ do-klayout_tech: @mkdir -p $(OBJECTS_DIR) cp $(TECH_LEF) $(OBJECTS_DIR)/klayout_tech.lef -KLAYOUT_ENV_VAR_IN_PATH_VERSION = 0.28.11 -KLAYOUT_VERSION := $(if $(KLAYOUT_CMD),$(shell $(KLAYOUT_CMD) -v 2>/dev/null | grep 'KLayout' | cut -d ' ' -f2),) - -KLAYOUT_ENV_VAR_IN_PATH = $(shell \ - if [ -z "$(KLAYOUT_VERSION)" ]; then \ - echo "not_found"; \ - elif [ "$$(echo -e "$(KLAYOUT_VERSION)\n$(KLAYOUT_ENV_VAR_IN_PATH_VERSION)" | sort -V | head -n1)" = "$(KLAYOUT_VERSION)" ] && [ "$(KLAYOUT_VERSION)" != "$(KLAYOUT_ENV_VAR_IN_PATH_VERSION)" ]; then \ - echo "invalid"; \ - else \ - echo "valid"; \ - fi) - $(OBJECTS_DIR)/klayout.lyt: $(KLAYOUT_TECH_FILE) $(OBJECTS_DIR)/klayout_tech.lef $(UNSET_AND_MAKE) do-klayout .PHONY: do-klayout do-klayout: ifeq ($(KLAYOUT_ENV_VAR_IN_PATH),valid) - SC_LEF_RELATIVE_PATH="$$\(env('FLOW_HOME')\)/$(shell realpath --relative-to=$(FLOW_HOME) $(SC_LEF))"; \ + SC_LEF_RELATIVE_PATH="$(shell realpath --relative-to=$(RESULTS_DIR) $(SC_LEF))"; \ OTHER_LEFS_RELATIVE_PATHS=$$(echo "$(foreach file, $(OBJECTS_DIR)/klayout_tech.lef $(ADDITIONAL_LEFS),$$(realpath --relative-to=$(RESULTS_DIR) $(file)))"); \ sed 's,.*,'"$$SC_LEF_RELATIVE_PATH"''"$$OTHER_LEFS_RELATIVE_PATHS"',g' $(KLAYOUT_TECH_FILE) > $(OBJECTS_DIR)/klayout.lyt else @@ -338,12 +162,6 @@ $(OBJECTS_DIR)/klayout_wrap.lyt: $(KLAYOUT_TECH_FILE) $(OBJECTS_DIR)/klayout_tec do-klayout_wrap: sed 's,.*,$(foreach file, $(OBJECTS_DIR)/klayout_tech.lef $(WRAP_LEFS),$(shell realpath --relative-to=$(OBJECTS_DIR)/def $(file))),g' $(KLAYOUT_TECH_FILE) > $(OBJECTS_DIR)/klayout_wrap.lyt -# Create Macro wrappers (if necessary) -# ============================================================================== -WRAP_CFG = $(PLATFORM_DIR)/wrapper.cfg - - -export TCLLIBPATH := util/cell-veneer $(TCLLIBPATH) $(WRAPPED_LEFS): mkdir -p $(OBJECTS_DIR)/lef $(OBJECTS_DIR)/def util/cell-veneer/wrap.tcl -cfg $(WRAP_CFG) -macro $(filter %$(notdir $(@:_mod.lef=.lef)),$(WRAP_LEFS)) @@ -362,8 +180,7 @@ $(WRAPPED_LIBS): # |____/ |_| |_| \_| |_| |_| |_|_____|____/___|____/ # .PHONY: synth -synth: $(RESULTS_DIR)/1_synth.v \ - $(RESULTS_DIR)/1_synth.sdc +synth: $(RESULTS_DIR)/1_synth.v .PHONY: synth-report synth-report: synth @@ -371,11 +188,14 @@ synth-report: synth .PHONY: do-synth-report do-synth-report: - ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/synth_metrics.tcl) 2>&1 | tee $(LOG_DIR)/1_1_yosys_metrics.log + ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/synth_metrics.tcl) 2>&1 | tee $(abspath $(LOG_DIR)/1_2_yosys_metrics.log) .PHONY: memory memory: - python3 $(SCRIPTS_DIR)/mem_dump.py $(RESULTS_DIR)/mem.json + if [ -f $(RESULTS_DIR)/mem_hierarchical.json ]; then \ + $(PYTHON_EXE) $(SCRIPTS_DIR)/mem_dump.py $(RESULTS_DIR)/mem_hierarchical.json; \ + fi + $(PYTHON_EXE) $(SCRIPTS_DIR)/mem_dump.py $(RESULTS_DIR)/mem.json # ============================================================================== @@ -383,65 +203,42 @@ memory: # Run Synthesis using yosys #------------------------------------------------------------------------------- -export SYNTH_SCRIPT ?= $(SCRIPTS_DIR)/synth.tcl -export SYNTH_MEMORY_MAX_BITS ?= 4096 - -.PHONY: do-yosys-keep-hierarchy -do-yosys-keep-hierarchy: - mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) - (export VERILOG_FILES=$(RESULTS_DIR)/1_synth.rtlil; \ - $(TIME_CMD) $(YOSYS_EXE) $(YOSYS_FLAGS) -c $(HIER_REPORT_SCRIPT)) 2>&1 | tee $(abspath $(LOG_DIR)/1_1_yosys_hier_report.log) - -export SDC_FILE_CLOCK_PERIOD = $(RESULTS_DIR)/clock_period.txt - $(SDC_FILE_CLOCK_PERIOD): $(SDC_FILE) mkdir -p $(dir $@) echo $(ABC_CLOCK_PERIOD_IN_PS) > $@ -YOSYS_DEPENDENCIES=$(DONT_USE_LIBS) $(WRAPPED_LIBS) $(DONT_USE_SC_LIB) $(DFF_LIB_FILE) $(VERILOG_FILES) $(CACHED_NETLIST) $(LATCH_MAP_FILE) $(ADDER_MAP_FILE) $(SDC_FILE_CLOCK_PERIOD) - .PHONY: yosys-dependencies yosys-dependencies: $(YOSYS_DEPENDENCIES) .PHONY: do-yosys -do-yosys: - mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) $(OBJECTS_DIR) - (export VERILOG_FILES=$(RESULTS_DIR)/1_synth.rtlil; \ - $(TIME_CMD) $(YOSYS_EXE) $(YOSYS_FLAGS) -c $(SYNTH_SCRIPT)) 2>&1 | tee $(abspath $(LOG_DIR)/1_1_yosys.log) +do-yosys: yosys-dependencies + $(SCRIPTS_DIR)/synth.sh $(SYNTH_SCRIPT) $(LOG_DIR)/1_2_yosys.log .PHONY: do-yosys-canonicalize do-yosys-canonicalize: yosys-dependencies - mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) $(OBJECTS_DIR) - # NOTE! YOSYS_FLAGS is omitted here because "-v 3" silences helpful error messages - ($(TIME_CMD) $(YOSYS_EXE) -c $(SCRIPTS_DIR)/synth_canonicalize.tcl) 2>&1 | tee $(abspath $(LOG_DIR)/1_1_yosys_canonicalize.log) + $(SCRIPTS_DIR)/synth.sh $(SCRIPTS_DIR)/synth_canonicalize.tcl $(LOG_DIR)/1_1_yosys_canonicalize.log -$(RESULTS_DIR)/1_synth.rtlil: $(YOSYS_DEPENDENCIES) +$(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil: $(YOSYS_DEPENDENCIES) $(UNSET_AND_MAKE) do-yosys-canonicalize -$(RESULTS_DIR)/1_1_yosys.v: $(RESULTS_DIR)/1_synth.rtlil - $(UNSET_AND_MAKE) do-yosys-keep-hierarchy do-yosys - -$(RESULTS_DIR)/1_synth.sdc: $(SDC_FILE) - mkdir -p $(RESULTS_DIR) - cp $(SDC_FILE) $(RESULTS_DIR)/1_synth.sdc +$(RESULTS_DIR)/1_2_yosys.v: $(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil + $(UNSET_AND_MAKE) do-yosys .PHONY: do-synth do-synth: mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) - cp $(RESULTS_DIR)/1_1_yosys.v $(RESULTS_DIR)/1_synth.v + cp $(RESULTS_DIR)/1_2_yosys.v $(RESULTS_DIR)/1_synth.v -$(RESULTS_DIR)/1_synth.v: $(RESULTS_DIR)/1_1_yosys.v +$(RESULTS_DIR)/1_synth.v: $(RESULTS_DIR)/1_2_yosys.v $(UNSET_AND_MAKE) do-synth .PHONY: clean_synth clean_synth: - rm -f $(RESULTS_DIR)/1_* $(RESULTS_DIR)/mem.json + rm -f $(RESULTS_DIR)/1_* $(RESULTS_DIR)/mem*.json rm -f $(REPORTS_DIR)/synth_* rm -f $(LOG_DIR)/1_* - rm -f $(SYNTH_STOP_MODULE_SCRIPT) + rm -f $(SYNTH_STATS) rm -f $(SDC_FILE_CLOCK_PERIOD) - rm -rf _tmp_yosys-abc-* - # ============================================================================== # _____ _ ___ ___ ____ ____ _ _ _ _ @@ -456,12 +253,6 @@ floorplan: $(RESULTS_DIR)/2_floorplan.odb \ # ============================================================================== -ifneq ($(FOOTPRINT),) -IS_CHIP = 1 -else ifneq ($(FOOTPRINT_TCL),) -IS_CHIP = 1 -endif - UNSET_VARS = for var in $(UNSET_VARIABLES_NAMES); do unset $$var; done # FILE_MAKEFILE is needed when ORFS is invoked with @@ -485,11 +276,16 @@ open_$(1): open_$(2) endef define OPEN_GUI -.PHONY: $(1)_$(2) -$(1)_$(2): - $(3)=$(RESULTS_DIR)/$(2) $(4) $(SCRIPTS_DIR)/gui.tcl +.PHONY: open_$(1) gui_$(1) +open_$(1): + $(2)=$(RESULTS_DIR)/$(1) $(OPENROAD_NO_EXIT_CMD) $(SCRIPTS_DIR)/open.tcl +gui_$(1): + $(2)=$(RESULTS_DIR)/$(1) $(OPENROAD_GUI_CMD) $(SCRIPTS_DIR)/open.tcl endef +# Enables "make gui_5_1_grt-failed" +$(eval $(call OPEN_GUI_SHORTCUT,5_1_grt-failed,5_1_grt-failed.odb)) + # Separate dependency checking and doing a step. This can # be useful to retest a stage without having to delete the # target, or when building a wafer thin layer on top of @@ -528,6 +324,7 @@ endif .PHONY: do-$(1) do-$(1): $(OBJECTS_DIR)/copyright.txt + $(SCRIPTS_DIR)/flow.sh $(1) $(3) @mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) $(OBJECTS_DIR) @echo Running $(3).tcl, stage $(1) @(set -eo pipefail; \ @@ -542,7 +339,7 @@ endef # # The file is copied within the $(RESULTS_DIR) # -# $(1) stem of target, e.g. 2_2_floorplan_io +# $(1) stem of target, e.g. 2_1_floorplan # $(2) basename of file to be copied # $(3) further dependencies # $(4) target extension, default .odb @@ -555,36 +352,31 @@ do-$(1)$(if $(4),$(4),): cp $(RESULTS_DIR)/$(2) $(RESULTS_DIR)/$(1)$(if $(4),$(4),.odb) endef +$(eval $(call do-step,1_3_synth,$(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc,synth_odb)) -# STEP 1: Translate verilog to odb -#------------------------------------------------------------------------------- -$(eval $(call do-step,2_1_floorplan,$(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(FOOTPRINT) $(SIG_MAP_FILE) $(FOOTPRINT_TCL),floorplan)) +$(eval $(call do-step,2_1_floorplan,$(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(FOOTPRINT) $(SIG_MAP_FILE) $(FOOTPRINT_TCL) $(LIB_FILES) $(IO_CONSTRAINTS),floorplan)) -$(eval $(call do-step,2_2_floorplan_io,$(RESULTS_DIR)/2_1_floorplan.odb $(IO_CONSTRAINTS),io_placement_random)) +$(eval $(call do-copy,2_floorplan,2_1_floorplan.sdc,,.sdc)) -# STEP 3: Timing Driven Mixed Sized Placement +# STEP 2: Macro Placement #------------------------------------------------------------------------------- -$(eval $(call do-step,2_3_floorplan_tdms,$(RESULTS_DIR)/2_2_floorplan_io.odb $(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc $(LIB_FILES),tdms_place)) +$(eval $(call do-step,2_2_floorplan_macro,$(RESULTS_DIR)/2_1_floorplan.odb $(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc $(MACRO_PLACEMENT) $(MACRO_PLACEMENT_TCL),macro_place)) -# STEP 4: Macro Placement +# STEP 3: Tapcell and Welltie insertion #------------------------------------------------------------------------------- -$(eval $(call do-step,2_4_floorplan_macro,$(RESULTS_DIR)/2_3_floorplan_tdms.odb $(RESULTS_DIR)/1_synth.v $(RESULTS_DIR)/1_synth.sdc $(MACRO_PLACEMENT) $(MACRO_PLACEMENT_TCL),macro_place)) +$(eval $(call do-step,2_3_floorplan_tapcell,$(RESULTS_DIR)/2_2_floorplan_macro.odb $(TAPCELL_TCL),tapcell)) -# STEP 5: Tapcell and Welltie insertion +# STEP 4: PDN generation #------------------------------------------------------------------------------- -$(eval $(call do-step,2_5_floorplan_tapcell,$(RESULTS_DIR)/2_4_floorplan_macro.odb $(TAPCELL_TCL),tapcell)) +$(eval $(call do-step,2_4_floorplan_pdn,$(RESULTS_DIR)/2_3_floorplan_tapcell.odb $(PDN_TCL),pdn)) -# STEP 6: PDN generation -#------------------------------------------------------------------------------- -$(eval $(call do-step,2_6_floorplan_pdn,$(RESULTS_DIR)/2_5_floorplan_tapcell.odb $(PDN_TCL),pdn)) - -$(eval $(call do-copy,2_floorplan,2_6_floorplan_pdn.odb,)) +$(eval $(call do-copy,2_floorplan,2_4_floorplan_pdn.odb,)) $(RESULTS_DIR)/2_floorplan.sdc: $(RESULTS_DIR)/2_1_floorplan.odb .PHONY: do-floorplan do-floorplan: - $(UNSET_AND_MAKE) do-2_1_floorplan do-2_2_floorplan_io do-2_3_floorplan_tdms do-2_4_floorplan_macro do-2_5_floorplan_tapcell do-2_6_floorplan_pdn do-2_floorplan + $(UNSET_AND_MAKE) do-2_1_floorplan do-2_2_floorplan_macro do-2_3_floorplan_tapcell do-2_4_floorplan_pdn do-2_floorplan do-2_floorplan.sdc .PHONY: clean_floorplan clean_floorplan: @@ -607,7 +399,7 @@ place: $(RESULTS_DIR)/3_place.odb \ #------------------------------------------------------------------------------- $(eval $(call do-step,3_1_place_gp_skip_io,$(RESULTS_DIR)/2_floorplan.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES),global_place_skip_io)) -$(eval $(call do-step,3_2_place_iop,$(RESULTS_DIR)/3_1_place_gp_skip_io.odb $(IO_CONSTRAINTS),io_placement)) +$(eval $(call do-step,3_2_place_iop,$(RESULTS_DIR)/3_1_place_gp_skip_io.odb,io_placement)) # STEP 3: Global placement with placed IOs, timing-driven, and routability-driven. #------------------------------------------------------------------------------- @@ -633,6 +425,12 @@ $(eval $(call do-copy,3_place,2_floorplan.sdc,,.sdc)) do-place: $(UNSET_AND_MAKE) do-3_1_place_gp_skip_io do-3_2_place_iop do-3_3_place_gp do-3_4_place_resized do-3_5_place_dp do-3_place do-3_place.sdc +# Custom repair_timing target after placement +$(eval $(call do-step,3_6_place_repair_timing,$(RESULTS_DIR)/3_5_place_dp.odb $(RESULTS_DIR)/3_place.sdc,repair_timing_post_place)) + +.PHONY: place_repair_timing +place_repair_timing: $(RESULTS_DIR)/3_6_place_repair_timing.odb + # Clean Targets #------------------------------------------------------------------------------- .PHONY: clean_place @@ -686,7 +484,8 @@ clean_cts: route: $(RESULTS_DIR)/5_route.odb \ $(RESULTS_DIR)/5_route.sdc -.PHONY: grt +.PHONY: grt globalroute +globalroute: grt grt: $(RESULTS_DIR)/5_1_grt.odb # ============================================================================== @@ -694,7 +493,7 @@ grt: $(RESULTS_DIR)/5_1_grt.odb # STEP 1: Run global route #------------------------------------------------------------------------------- -$(eval $(call do-step,5_1_grt,$(RESULTS_DIR)/4_cts.odb $(FASTROUTE_TCL) $(PRE_GLOBAL_ROUTE),global_route)) +$(eval $(call do-step,5_1_grt,$(RESULTS_DIR)/4_cts.odb $(FASTROUTE_TCL) $(PRE_GLOBAL_ROUTE_TCL),global_route)) # STEP 2: Run detailed route #------------------------------------------------------------------------------- @@ -704,16 +503,18 @@ $(eval $(call do-step,5_3_fillcell,$(RESULTS_DIR)/5_2_route.odb,fillcell)) $(eval $(call do-copy,5_route,5_3_fillcell.odb)) -$(eval $(call do-copy,5_route,4_cts.sdc,,.sdc)) +$(eval $(call do-copy,5_route,5_1_grt.sdc,,.sdc)) .PHONY: do-route do-route: $(UNSET_AND_MAKE) do-5_1_grt do-5_2_route do-5_3_fillcell do-5_route do-5_route.sdc +.PHONY: do-grt +do-grt: + $(UNSET_AND_MAKE) do-5_1_grt + .PHONY: clean_route clean_route: - rm -rf output*/ results*.out.dmp layer_*.mps - rm -rf *.gdid *.log *.met *.sav *.res.dmp rm -rf $(RESULTS_DIR)/route.guide $(RESULTS_DIR)/output_guide.mod $(RESULTS_DIR)/updated_clks.sdc rm -rf $(RESULTS_DIR)/5_*.odb $(RESULTS_DIR)/5_route.sdc $(RESULTS_DIR)/5_*.def $(RESULTS_DIR)/5_*.v rm -f $(REPORTS_DIR)/5_* @@ -721,16 +522,14 @@ clean_route: .PHONY: klayout_tr_rpt klayout_tr_rpt: $(RESULTS_DIR)/5_route.def $(OBJECTS_DIR)/klayout.lyt - $(call KLAYOUT_FOUND) - $(KLAYOUT_CMD) -rd in_drc="$(REPORTS_DIR)/5_route_drc.rpt" \ + $(SCRIPTS_DIR)/klayout.sh -rd in_drc="$(REPORTS_DIR)/5_route_drc.rpt" \ -rd in_def="$<" \ -rd tech_file=$(OBJECTS_DIR)/klayout.lyt \ -rm $(UTILS_DIR)/viewDrc.py .PHONY: klayout_guides klayout_guides: $(RESULTS_DIR)/5_route.def $(OBJECTS_DIR)/klayout.lyt - $(call KLAYOUT_FOUND) - $(KLAYOUT_CMD) -rd in_guide="$(RESULTS_DIR)/route.guide" \ + $(SCRIPTS_DIR)/klayout.sh -rd in_guide="$(RESULTS_DIR)/route.guide" \ -rd in_def="$<" \ -rd net_name=$(GUIDE_NET) \ -rd tech_file=$(OBJECTS_DIR)/klayout.lyt \ @@ -743,7 +542,7 @@ klayout_guides: $(RESULTS_DIR)/5_route.def $(OBJECTS_DIR)/klayout.lyt # | _| | || |\ || | ___) | _ || || |\ | |_| | # |_| |___|_| \_|___|____/|_| |_|___|_| \_|\____| # -GDS_FINAL_FILE = $(RESULTS_DIR)/6_final.$(STREAM_SYSTEM_EXT) + .PHONY: finish finish: $(LOG_DIR)/6_report.log \ $(RESULTS_DIR)/6_final.v \ @@ -758,12 +557,12 @@ tunereport: $(LOG_DIR)/6_report.log \ .PHONY: elapsed elapsed: - -@$(UTILS_DIR)/genElapsedTime.py -d $(BLOCK_LOG_FOLDERS) $(LOG_DIR) + -@$(PYTHON_EXE) $(UTILS_DIR)/genElapsedTime.py -d $(BLOCK_LOG_FOLDERS) $(LOG_DIR) # Useful when working with macros, see elapsed time for all macros in platform .PHONY: elapsed-all elapsed-all: - @$(UTILS_DIR)/genElapsedTime.py -d $(shell find $(WORK_HOME)/logs/$(PLATFORM)/*/*/ -type d) + @$(PYTHON_EXE) $(UTILS_DIR)/genElapsedTime.py -d $(shell find $(WORK_HOME)/logs/$(PLATFORM)/*/*/ -type d) $(eval $(call do-step,6_1_fill,$(RESULTS_DIR)/5_route.odb $(RESULTS_DIR)/5_route.sdc $(FILL_CONFIG),density_fill)) @@ -795,7 +594,7 @@ generate_abstract: $(RESULTS_DIR)/6_final.gds $(RESULTS_DIR)/6_final.def $(RESU .PHONY: do-generate_abstract do-generate_abstract: mkdir -p $(LOG_DIR) $(REPORTS_DIR) - ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/generate_abstract.tcl -metrics $(LOG_DIR)/generate_abstract.json) 2>&1 | tee $(LOG_DIR)/generate_abstract.log + ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/generate_abstract.tcl -metrics $(LOG_DIR)/generate_abstract.json) 2>&1 | tee $(abspath $(LOG_DIR)/generate_abstract.log) .PHONY: clean_abstract clean_abstract: @@ -804,8 +603,7 @@ clean_abstract: # Merge wrapped macros using Klayout #------------------------------------------------------------------------------- $(WRAPPED_GDSOAS): $(OBJECTS_DIR)/klayout_wrap.lyt $(WRAPPED_LEFS) - $(call KLAYOUT_FOUND) - ($(TIME_CMD) $(KLAYOUT_CMD) -zz -rd design_name=$(basename $(notdir $@)) \ + ($(TIME_CMD) $(SCRIPTS_DIR)/klayout.sh -zz -rd design_name=$(basename $(notdir $@)) \ -rd in_def=$(OBJECTS_DIR)/def/$(notdir $(@:$(STREAM_SYSTEM_EXT)=def)) \ -rd in_files="$(ADDITIONAL_GDSOAS)" \ -rd config_file=$(FILL_CONFIG) \ @@ -813,25 +611,23 @@ $(WRAPPED_GDSOAS): $(OBJECTS_DIR)/klayout_wrap.lyt $(WRAPPED_LEFS) -rd out_file=$@ \ -rd tech_file=$(OBJECTS_DIR)/klayout_wrap.lyt \ -rd layer_map=$(GDS_LAYER_MAP) \ - -r $(UTILS_DIR)/def2stream.py) 2>&1 | tee $(LOG_DIR)/6_merge_$(basename $(notdir $@)).log + -r $(UTILS_DIR)/def2stream.py) 2>&1 | tee $(abspath $(LOG_DIR)/6_merge_$(basename $(notdir $@)).log) # Merge GDS using Klayout #------------------------------------------------------------------------------- -GDS_MERGED_FILE = $(RESULTS_DIR)/6_1_merged.$(STREAM_SYSTEM_EXT) $(GDS_MERGED_FILE): $(RESULTS_DIR)/6_final.def $(OBJECTS_DIR)/klayout.lyt $(GDSOAS_FILES) $(WRAPPED_GDSOAS) $(SEAL_GDSOAS) $(UNSET_AND_MAKE) do-gds-merged .PHONY: do-gds-merged do-gds-merged: - $(call KLAYOUT_FOUND) - ($(TIME_CMD) $(STDBUF_CMD) $(KLAYOUT_CMD) -zz -rd design_name=$(DESIGN_NAME) \ + ($(TIME_CMD) $(STDBUF_CMD) $(SCRIPTS_DIR)/klayout.sh -zz -rd design_name=$(DESIGN_NAME) \ -rd in_def=$(RESULTS_DIR)/6_final.def \ -rd in_files="$(GDSOAS_FILES) $(WRAPPED_GDSOAS)" \ -rd seal_file="$(SEAL_GDSOAS)" \ -rd out_file=$(GDS_MERGED_FILE) \ -rd tech_file=$(OBJECTS_DIR)/klayout.lyt \ -rd layer_map=$(GDS_LAYER_MAP) \ - -r $(UTILS_DIR)/def2stream.py) 2>&1 | tee $(LOG_DIR)/6_1_merge.log + -r $(UTILS_DIR)/def2stream.py) 2>&1 | tee $(abspath $(LOG_DIR)/6_1_merge.log) $(RESULTS_DIR)/6_final.v: $(LOG_DIR)/6_report.log @@ -848,10 +644,9 @@ drc: $(REPORTS_DIR)/6_drc.lyrdb $(REPORTS_DIR)/6_drc.lyrdb: $(GDS_FINAL_FILE) $(KLAYOUT_DRC_FILE) ifneq ($(KLAYOUT_DRC_FILE),) - $(call KLAYOUT_FOUND) - ($(TIME_CMD) $(KLAYOUT_CMD) -zz -rd in_gds="$<" \ + ($(TIME_CMD) $(SCRIPTS_DIR)/klayout.sh -zz -rd in_gds="$<" \ -rd report_file=$(abspath $@) \ - -r $(KLAYOUT_DRC_FILE)) 2>&1 | tee $(LOG_DIR)/6_drc.log + -r $(KLAYOUT_DRC_FILE)) 2>&1 | tee $(abspath $(LOG_DIR)/6_drc.log) # Hacky way of getting DRV count (don't error on no matches) grep -c "" $@ > $(REPORTS_DIR)/6_drc_count.rpt || [[ $$? == 1 ]] else @@ -859,7 +654,7 @@ else endif $(RESULTS_DIR)/6_final.cdl: $(RESULTS_DIR)/6_final.v - ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/cdl.tcl) 2>&1 | tee $(LOG_DIR)/6_cdl.log + ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/cdl.tcl) 2>&1 | tee $(abspath $(LOG_DIR)/6_cdl.log) $(OBJECTS_DIR)/6_final_concat.cdl: $(RESULTS_DIR)/6_final.cdl $(CDL_FILE) cat $^ > $@ @@ -869,11 +664,10 @@ lvs: $(RESULTS_DIR)/6_lvs.lvsdb $(RESULTS_DIR)/6_lvs.lvsdb: $(GDS_FINAL_FILE) $(KLAYOUT_LVS_FILE) $(OBJECTS_DIR)/6_final_concat.cdl ifneq ($(KLAYOUT_LVS_FILE),) - $(call KLAYOUT_FOUND) - ($(TIME_CMD) $(KLAYOUT_CMD) -b -rd in_gds="$<" \ + ($(TIME_CMD) $(SCRIPTS_DIR)/klayout.sh -b -rd in_gds="$<" \ -rd cdl_file=$(abspath $(OBJECTS_DIR)/6_final_concat.cdl) \ -rd report_file=$(abspath $@) \ - -r $(KLAYOUT_LVS_FILE)) 2>&1 | tee $(LOG_DIR)/6_lvs.log + -r $(KLAYOUT_LVS_FILE)) 2>&1 | tee $(abspath $(LOG_DIR)/6_lvs.log) else echo "LVS not supported on this platform" > $@ endif @@ -894,8 +688,22 @@ clean_finish: # # ============================================================================== +.PHONY: check-openroad +check-openroad: + @if [ "$(strip $(OPENROAD_IS_VALID))" != "true" ]; then \ + echo "OPENROAD_EXE is set to '$(OPENROAD_EXE)', but it is either not found or not executable."; \ + exit 1; \ + fi + +.PHONY: check-yosys +check-yosys: + @if [ "$(strip $(YOSYS_IS_VALID))" != "true" ]; then \ + echo "YOSYS_EXE is set to '$(YOSYS_EXE)', but it is either not found or not executable."; \ + exit 1; \ + fi + .PHONY: all -all: synth floorplan place cts route finish +all: check-yosys check-openroad synth floorplan place cts route finish .PHONY: clean clean: @@ -909,34 +717,21 @@ clean: clean_all: clean_synth clean_floorplan clean_place clean_cts clean_route clean_finish clean_metadata clean_abstract rm -rf $(OBJECTS_DIR) +clean_metadata: + @echo "clean_metadata: nothing to clean." + .PHONY: nuke nuke: clean_test clean_issues - rm -rf ./results ./logs ./reports ./objects - rm -rf layer_*.mps macrocell.list *best.plt *_pdn.def - rm -rf *.rpt *.rpt.old *.def.v pin_dumper.log - rm -f $(OBJECTS_DIR)/versions.txt $(OBJECTS_DIR)/copyright.txt dummy.guide - -.PHONY: vars -vars: - $(UTILS_DIR)/generate-vars.sh vars + rm -rf $(WORK_HOME)/results $(WORK_HOME)/logs $(WORK_HOME)/reports $(WORK_HOME)/objects + rm -f $(OBJECTS_DIR)/copyright.txt # DEF/GDS/OAS viewer shortcuts #------------------------------------------------------------------------------- -RESULTS_ODB = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.odb))) -RESULTS_DEF = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.def))) -RESULTS_GDS = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.gds))) -RESULTS_OAS = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.oas))) .PHONY: $(foreach file,$(RESULTS_DEF) $(RESULTS_GDS) $(RESULTS_OAS),klayout_$(file)) $(foreach file,$(RESULTS_DEF) $(RESULTS_GDS) $(RESULTS_OAS),klayout_$(file)): klayout_%: $(OBJECTS_DIR)/klayout.lyt - $(KLAYOUT_CMD) -nn $(OBJECTS_DIR)/klayout.lyt $(RESULTS_DIR)/$* - -.PHONY: gui_synth -gui_synth: - $(OPENROAD_GUI_CMD) $(SCRIPTS_DIR)/sta-synth.tcl -.PHONY: open_synth -open_synth: - $(OPENROAD_NO_EXIT_CMD) $(SCRIPTS_DIR)/sta-synth.tcl + $(SCRIPTS_DIR)/klayout.sh -nn $(OBJECTS_DIR)/klayout.lyt $(RESULTS_DIR)/$* +$(eval $(call OPEN_GUI_SHORTCUT,synth,1_synth.odb)) $(eval $(call OPEN_GUI_SHORTCUT,floorplan,2_floorplan.odb)) $(eval $(call OPEN_GUI_SHORTCUT,place,3_place.odb)) $(eval $(call OPEN_GUI_SHORTCUT,cts,4_cts.odb)) @@ -944,10 +739,8 @@ $(eval $(call OPEN_GUI_SHORTCUT,route,5_route.odb)) $(eval $(call OPEN_GUI_SHORTCUT,grt,5_1_grt.odb)) $(eval $(call OPEN_GUI_SHORTCUT,final,6_final.odb)) -$(foreach file,$(RESULTS_DEF),$(eval $(call OPEN_GUI,gui,$(file),DEF_FILE,$(OPENROAD_GUI_CMD)))) -$(foreach file,$(RESULTS_ODB),$(eval $(call OPEN_GUI,gui,$(file),ODB_FILE,$(OPENROAD_GUI_CMD)))) -$(foreach file,$(RESULTS_DEF),$(eval $(call OPEN_GUI,open,$(file),DEF_FILE,$(OPENROAD_NO_EXIT_CMD)))) -$(foreach file,$(RESULTS_ODB),$(eval $(call OPEN_GUI,open,$(file),ODB_FILE,$(OPENROAD_NO_EXIT_CMD)))) +$(foreach file,$(RESULTS_DEF),$(eval $(call OPEN_GUI,$(file),DEF_FILE))) +$(foreach file,$(RESULTS_ODB),$(eval $(call OPEN_GUI,$(file),ODB_FILE))) # Write a def for the corresponding odb $(foreach file,$(RESULTS_ODB),$(file).def): %.def: @@ -977,23 +770,14 @@ all_verilog : $(foreach file,$(RESULTS_ODB),$(file).v) .PHONY: handoff handoff : all_defs all_verilog -.PHONY: print-% -# Print any variable, for instance: make print-DIE_AREA -print-% : ; @echo "$* = $($*)" - .PHONY: test-unset-and-make-% test-unset-and-make-%: ; $(UNSET_AND_MAKE) $* .phony: klayout klayout: - $(KLAYOUT_CMD) + $(SCRIPTS_DIR)/klayout.sh .phony: run run: - $(OPENROAD_CMD) -no_splash $(RUN_SCRIPT) - -# Utilities -#------------------------------------------------------------------------------- -include $(UTILS_DIR)/utils.mk -export PRIVATE_DIR ?= ../../private_tool_scripts --include $(PRIVATE_DIR)/private.mk + @mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) $(OBJECTS_DIR) + ($(OPENROAD_CMD) -no_splash $(if $(filter %.py,$(RUN_SCRIPT)),-pyth diff --git a/flow-Agent/README.md b/flow-Agent/README.md index 4b67310..15edd1a 100644 --- a/flow-Agent/README.md +++ b/flow-Agent/README.md @@ -1,34 +1,77 @@ -# ORFS-Agent: Tool-Using Agents for Chip Design Optimization +# A2-ORFO: Autonomous Agent for Intelligent OpenROAD Flow Optimization ## Overview - -ORFS-Agent is an LLM-based iterative optimization agent for automating parameter tuning in open-source hardware design flows. This implementation integrates with OpenROAD-flow-scripts (ORFS) to optimize chip design parameters using large language models that adaptively explore and refine parameter configurations. - -The agent demonstrates improvements in wirelength and effective clock period by over 13% while using 40% fewer optimization iterations compared to baseline Bayesian optimization approaches. The framework is modular and model-agnostic, working with different LLMs without requiring fine-tuning. - +We expand ([ORFS-Agent](https://github.com/ABKGroup/ORFS-Agent#)) into a complete intelligent agent system, namely A2-ORFO (Autonomous Agent for Intelligent OpenROAD Flow Optimization), so that it can retrieve and invoke the information of the knowledge base in a specific domain to tell us how to fix errors. And combine the global search capability of Large Language Models(LLMs) and the efficient sampling Bayesian Optimization (BO) algorithm to conduct hybrid parameter tuning optimization. Combine LLMs agents with BO and use LLMs agents to replace the three basic capabilities of human engineers, including: The ability to retrieve existing knowledge, analyze and think about planning (debugging and comparing historical data), and the ability to use tools (BO, Genetic Algorithm, MCTS), endowing them with stronger perception ability, transfer memory and interpretability. + +The agent demonstrates improvements in wirelength and effective clock period by over XX% while using XX% fewer optimization iterations compared to baseline Bayesian optimization approaches and over XX% while using XX% fewer optimization iterations compared to ORFS-Agent. The framework is modular and model-agnostic, working with different LLMs without requiring fine-tuning. + +

+ expanding figure +

+ +## Contents +- [Framework of A2-ORFO](#Framework-of-A2-ORFO) +- [Project Structure](#Project-Structure) + - [Core Modules](#Core-Modules) + - [Relevant Execution Scripts](#Relevant-Execution-Scripts) + - [Parameter Constraints Files](#Parameter-Constraints-Files) + - [Helper Utilities](#Helper-Utilities) +- [Key Features](#Key-Features) +- [Environment Setup](#Environment-Setup) + - [Prerequisites](#Prerequisites) + - [Environment Setup](#Environment-Setup) + - [Python Environment Setup](#Python-Environment-Setup) + - [Python Dependencies](#Python-Dependencies) + - [System Environment Setup](#System-Environment-Setup) + - [System Dependencies](#System-Dependencies) +- [Operating Instructions](#Operating-Instructions) + - [Parameter Configuration](#Parameter-Configuration) + - [Design-Specific Configuration](#Design-Specific-Configuration) + - [Resource Planning](#Resource-Planning) + - [API Key Setup](#API-Key-Setup) + - [Running the Optimization](#Running-the-Optimization) + - [Basic Usage](#Basic-Usage) + - [Command Line Options](#Command-Line-Options) + - [Example Runs](#Example-Runs) + - [Output Structure](#Output-Structure) +- [Experimental Results](#Experimental-Results) + +## Framework of A2-ORFO + +The framework of A2-ORFO Agent is shown in the left figure below , and the relevant details are introduced on the right below. + +

+ framework figure +

## Project Structure The ORFS-Agent consists of several key components: -### Core Python Modules +### Core Modules -- **`optimize.py`**: Main optimization script that processes OpenROAD log files and coordinates the optimization workflow +- **`optimize.py`**: Main optimization script using RAG and ReAct techniques to process OpenROAD log files, error messages and optimize the RTL-GDSII flow. Including call the LLM to retrieve existing knowledge to assist optimization and analyze and think about planning to improve the accuracy of the output results under the ReAct framework - **`inspectfuncs.py`**: Data analysis and inspection tools for understanding parameter space and design metrics - **`modelfuncs.py`**: Machine learning utilities including Gaussian Process modeling, kernel selection, and preprocessing - **`agglomfuncs.py`**: Data aggregation and synthesis functions for combining results across multiple runs - **`constraint_optimizer.py`**: Constraint handling and parameter space definition -- **`prompts.py`**: LLM prompt templates and interaction management +- **`AutoTuner-integration`**:The code file integrates the internal Bayesian parameter optimizer Auto-Tuner of ORFS +- **`EDA-Corpus-main/`**:Stores knowledge bases and corpus resources related to design optimization. +- **`rag/`**:Contains the relevant code and configuration files of the RAG framework and is used to implement the +- **`rag_data/`**:Stores retrieval databases, design logs, error samples, and knowledge index files. +- **`models/`**:Stores trained models, vectorized weights, and embedding files to support model inference and knowledge retrieval. +- **`comparison/`**:Contains baseline code to be compared. -### Execution Scripts +### Relevant Execution Scripts - **`maindriver.sh`**: Primary execution script that orchestrates the entire optimization workflow - **`run_sequential.sh`**: Handles sequential optimization phases and parameter generation - **`run_parallel.sh`**: Manages parallel execution of multiple design runs - **`Makefile`**: Modified OpenROAD Makefile supporting parallel runs with INT_PARAM configuration +- **`opt_config.json`**: Parameter constraints, ranges, and optimization settings for different design-PDK combinations +- **`INSTRUCTIONS.md`**: Setup and execution instructions -### Configuration Files - +### Parameter Constraints Files - **`opt_config.json`**: Parameter constraints, ranges, and optimization settings for different design-PDK combinations - **`INSTRUCTIONS.md`**: Setup and execution instructions @@ -40,6 +83,8 @@ The ORFS-Agent consists of several key components: ## Key Features +- **RAG**: Retrieve existing knowledge to assist optimization. +- **ReAct Framework**: Analyze and think about planning to improve the accuracy of the output results with local and global optimization - **Multi-objective Optimization**: Supports optimization of Effective Clock Period (ECP), wirelength (WL), or weighted combinations - **Parallel Execution**: Efficient parallel processing of multiple design configurations - **Adaptive Parameter Exploration**: LLM-guided parameter space exploration with constraint handling @@ -50,54 +95,49 @@ The ORFS-Agent consists of several key components: ### Prerequisites -1. **OpenROAD-flow-scripts**: Install and configure OpenROAD-flow-scripts from the specific commit ([ce8d36a](https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts/tree/ce8d36a)) referenced in the paper. -2. **Operating System**: Ubuntu/Debian-based system (required) -3. **Hardware Resources**: +1. **OpenROAD-flow-scripts**: Install and configure ORFS-Research. In order to support the parallel execution of multiple tasks, the Makefile of OpenROAD-flow-scripts needs to be adjusted appropriately: the original single configuration file mechanism is changed to the parametric form, that is, from a single config.mk to config_{INT_PARAM}.mk; Add the INT_PARAM variable in the Makefile to distinguish parallel task instances; Use the provided Makefile as a reference for the required changes. +2. **ORFS-Agent**: Install and configure ORFS-Agent from the address ([ORFS-Agent](https://github.com/ABKGroup/ORFS-Agent#)). In order to unify and optimize logic and interfaces, we need to replace the original identical files in the ORFS-Agent library with the files in the current library. Different files in the ORFS-Agent library will be retained. +3. **Operating System**: Ubuntu/Debian-based system +4. **Hardware Resources**: - Minimum 8 vCPUs per parallel run - 8+ GB RAM per parallel run (20-25GB for larger circuits like JPEG) - For default configuration: 110 vCPUs and 220GB RAM total -### Python Environment Setup +### Environment Setup +#### Python Environment Setup ```bash # Create virtual environment python3 -m venv .venv_orfs_agent source .venv_orfs_agent/bin/activate # Install required packages -pip install numpy pandas scikit-learn scipy anthropic python-dotenv scikit-optimize +pip install numpy pandas scikit-learn scipy python-dotenv scikit-optimize openai torch ``` -### Required Dependencies - -The system requires the following Python packages: +#### Python Dependencies - `numpy` - Numerical computing - `pandas` - Data manipulation and analysis - `scikit-learn` - Machine learning utilities - `scipy` - Scientific computing -- `anthropic` - LLM API integration (if using Anthropic models) +- `openai` - LLM API integration (if using openai models) - `python-dotenv` - Environment variable management - `scikit-optimize` - Bayesian optimization +- `torch (pytorch)` - Numerical computing -### Additional System Dependencies - +#### System Environment Setup ```bash # Install required system tools sudo apt-get update sudo apt-get install jq bc timeout ``` +#### System Dependencies +- `jq` - used for parsing and processing JSON data in the command line +- `bc` - Command-line Calculator, used for precise numerical operations +- `timeout` - Used to limit the execution time of a command or script -## Configuration - -### 1. OpenROAD-flow-scripts Setup - -First, modify your OpenROAD Makefile to support parallel runs: - -- Replace single `DESIGN_CONFIG` with multiple parametrized configurations. Instead of a single `config.mk`, the flow uses `config_{INT_PARAM}.mk` to enable parallel runs. -- Add `INT_PARAM` support for parallel execution. -- Use the provided [Makefile](./Makefile) as a reference for required changes. - -### 2. Parameter Configuration +## Operating Instructions +### Parameter Configuration Edit `opt_config.json` to define: @@ -123,7 +163,7 @@ Example configuration structure: } ``` -### 3. Design-Specific Configuration +### Design-Specific Configuration Before running an optimization, you may need to adjust the `config.mk` file for your chosen design, as the default files may not define all tunable parameters. @@ -137,7 +177,7 @@ Before running an optimization, you may need to adjust the `config.mk` file for - **TCL Scripts**: Ensure you are using the provided custom TCL scripts (`fastasap.tcl`, `fastsky.tcl`). You must link these in the `config.mk` file for your design. Refer to the example configuration changes in `exampleaes/configchanges.mk` for guidance. -### 4. Resource Planning +### Resource Planning Configure resource allocation in `maindriver.sh`: @@ -153,18 +193,19 @@ ECP_WEIGHT_SURROGATE=0.5 # Weight for post-CTS ECP in the surrogate model WL_WEIGHT_SURROGATE=0.5 # Weight for post-CTS WL in the surrogate model ``` -### 5. API Key Setup +### API Key Setup The agent requires API keys for LLM providers. You will need to add them directly into the source code: -- **Anthropic API Key**: In `optimize.py`, find the placeholder for the Anthropic API key and insert your key. -- **OpenAI API Key**: In `prompts.py`, find the placeholder for the OpenAI API key and insert your key. This is required for prompt generation functionalities. +- **OpenAI API Key**: In `optimize.py`, find the placeholder for the OpenAI API key and insert your key. This is required for prompt generation functionalities. **Note**: For improved security, consider modifying the scripts to load keys from environment variables using the `python-dotenv` package. -## Running the Optimization +### Running the Optimization -### Basic Usage +Although our internal optimization framework processes are different, the usage is the same as that of ORFS-Agent + +#### Basic Usage ```bash # Make scripts executable @@ -174,7 +215,7 @@ chmod +x maindriver.sh run_parallel.sh run_sequential.sh ./maindriver.sh -p -d [options] ``` -### Command Line Options +#### Command Line Options - **`-p, --platform`**: Target PDK (`asap7` or `sky130hd`) - **`-d, --design`**: Circuit design (`aes`, `ibex`, or `jpeg`) @@ -183,7 +224,7 @@ chmod +x maindriver.sh run_parallel.sh run_sequential.sh - **`-t, --timeout`**: Timeout per run (default: 45m) - **`-o, --objective`**: Optimization goal (`ECP`, `DWL`, or `COMBO`) -### Example Runs +#### Example Runs ```bash # Optimize AES circuit on ASAP7 for ECP @@ -194,9 +235,16 @@ chmod +x maindriver.sh run_parallel.sh run_sequential.sh # Large circuit optimization (JPEG) ./maindriver.sh -p asap7 -d jpeg -o DWL -r 20 -t 90m + +# Directly run 6 examples of DWL optimization in full sequence +chmod +x run_all.sh +./run_all.sh + +# Optimize AES circuit on ASAP7 for ECP with sub-stage and dual supervision framework +./maindriver_stage.sh -p asap7 -d aes -o ECP ``` -## Output Structure +#### Output Structure Each optimization run generates: @@ -209,25 +257,76 @@ Each optimization run generates: - **`logs/`**: Real-time execution logs organized by platform/design - **CSV files**: Parameter configurations and results tracking +Note that the results of the original paper were obtained with Claude-3.5 Sonnet and you *must* ensure that your key for replication and/or running of the tool can support frequent tool calls to the model. -## License - -This project is licensed under the BSD 3-Clause License. See the `LICENSE` file for details. - -## Citation - -This work is based on the research paper: - -**ORFS-agent: Tool-Using Agents for Chip Design Optimization** -*Amur Ghose, Andrew B. Kahng, Sayak Kundu, and Zhiang Wang* -University of California San Diego -arXiv:2506.08332v1 [cs.AI] 12 Jun 2025 | MLCAD 2025 -Available at: https://arxiv.org/pdf/2506.08332 - -## PLEASE READ CAREFULLY FOR REPLICATION, REPRODUCTION AND USAGE ! - -For the purposes of replication or usage, you may be interested in using this as a flow within OR-AutoTuner, OpenROAD's official BO tool. - -Look within the AutoTuner-integration folder for an example of this. Within the ORFS-with-AutoTuner subdirectory, a more streamlined version of ORFS-agent appears in orfs_agent.py, which can be useful if you wish to run your experiments with a restrictive time and/or token budget. +## Experimental Results +Iterate for 20 rounds, parallelize 4 tasks, 12 optimization params, api=deepseek-V3, and only optimize DWL: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TechCircuitORFS default flow
(no agent)
ORFS-Agent with
deepseek api (baseline)
RAG onlyReAct onlyBoth RAG and ReAct
WLECP*WLECP*WLECP*WLECP*WLECP*
SKY
130HD
JPEG20815298.022793116.9522903307.9023033718.3922290248.63
IBEX108283710.011803768.67112165711.65104441811.4010442879.49
AES8061894.58442904.697744975.568735813.638316084.69
ASAP7IBEX1492531260138616922.43172498891.37140398925.901486241314.52
AES113447400117369389.09101258312.08103820484.8596012465.68
-Note that the results of the original paper were obtained with Claude-3.5 Sonnet and you *must* ensure that your key for replication and/or running of the tool can support frequent tool calls to the model. diff --git a/flow-Agent/comparison/optimize_orfs-agent_claude+llm.py b/flow-Agent/comparison/optimize_orfs-agent_claude+llm.py new file mode 100644 index 0000000..60dcee8 --- /dev/null +++ b/flow-Agent/comparison/optimize_orfs-agent_claude+llm.py @@ -0,0 +1,1273 @@ +#!/usr/bin/env python3 + +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random + +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + + # Determine success based on completion markers and errors + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics +# def extract_timing_metrics(log_content: str) -> Dict[str, float]: +# """Extract timing-related metrics from log content""" +# metrics = {} + +# # Extract worst slack (final) +# slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if slack_match: +# metrics['worst_slack'] = float(slack_match.group(1)) + +# # Extract CTS worst slack +# cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if cts_slack_match: +# metrics['cts_ws'] = float(cts_slack_match.group(1)) + +# # Extract clock period +# period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) +# if period_match: +# metrics['clock_period'] = float(period_match.group(1)) + +# # Extract TNS +# tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if tns_match: +# metrics['tns'] = float(tns_match.group(1)) + +# return metrics + +# def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: +# """Extract wirelength-related metrics from log content""" +# metrics = {} + +# # Extract total wirelength +# wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) +# if wl_match: +# metrics['total_wirelength'] = float(wl_match.group(1)) + +# # Extract estimated wirelength after CTS +# cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) +# if cts_wl_match: +# metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + +# return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str]) -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully', + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + def _build_error_context(self, data: Dict[str, Any]) -> str: + """Summarize errors across runs so the LLM can diagnose failures""" + log_data = data.get('log_data') or {} + runs = log_data.get('runs') or [] + if not runs: + return "No run history available for diagnostics yet." + + summary = log_data.get('summary') or {} + total_runs = summary.get('total_runs', len(runs)) + failed_runs = summary.get('failed_runs', sum(1 for run in runs if not run.get('success', True))) + successful_runs = summary.get('successful_runs', total_runs - failed_runs) + runs_with_errors = sum(1 for run in runs if run.get('errors')) + + error_buckets: Dict[str, Dict[str, Any]] = {} + failure_examples = [] + + for run in runs: + run_label = run.get('run_id') or run.get('file') or (run.get('files') or ["unknown"])[0] + run_files = [os.path.basename(f) for f in run.get('files', [])] + run_errors = [" ".join(err.split()) for err in run.get('errors', [])] + + if not run.get('success', True) or run_errors: + failure_examples.append({ + 'run': run_label, + 'files': run_files[:2], + 'errors': run_errors[:3], + 'metrics': { + key: run.get('metrics', {}).get(key) + for key in ['worst_slack', 'tns', 'cts_ws', 'total_wirelength'] + if key in run.get('metrics', {}) + } + }) + + for err in run_errors: + bucket = error_buckets.setdefault(err, {'count': 0, 'runs': set(), 'files': set()}) + bucket['count'] += 1 + bucket['runs'].add(run_label) + bucket['files'].update(run_files) + + summary_lines = [ + f"Total runs analyzed: {total_runs}", + f"Successful: {successful_runs}, Failed: {failed_runs}, Runs with explicit errors: {runs_with_errors}" + ] + + if error_buckets: + summary_lines.append("Top recurring error signatures (max 5):") + sorted_errors = sorted(error_buckets.items(), key=lambda kv: kv[1]['count'], reverse=True) + for idx, (msg, info) in enumerate(sorted_errors[:5], start=1): + runs_list = ", ".join(sorted(info['runs'])) or "unknown" + files_list = ", ".join(sorted(info['files'])) or "unknown" + summary_lines.append( + f" {idx}. '{msg}' | count={info['count']} | runs={runs_list} | files={files_list}" + ) + else: + summary_lines.append("No explicit error strings were found in the available logs.") + + if failure_examples: + summary_lines.append("Sample failing runs with metric snapshots:") + for example in failure_examples[:3]: + file_info = ", ".join(example['files']) if example['files'] else "unknown file" + error_info = "; ".join(example['errors']) if example['errors'] else "No explicit errors logged" + metric_info = ", ".join(f"{k}={v}" for k, v in example['metrics'].items()) or "metrics unavailable" + summary_lines.append( + f" - Run {example['run']} ({file_info}): errors={error_info}; metrics={metric_info}" + ) + + return "\n".join(summary_lines) + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """Generate LLM prompt for different stages""" + + # Include parameter constraints in the prompt + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + error_context = self._build_error_context(data) + error_prompt_prefix = ( + "Error and failure diagnostics extracted from logs:\n" + f"{error_context}\n\n" + "Use the above diagnostics to reason about likely failure modes, " + "root causes, and mitigation strategies while answering the following tasks.\n\n" + ) + print(f"[DEBUG] error_prompt_prefix:\n{error_prompt_prefix}") + + # Construct the prompt based on the stage + if stage == 'inspect': + prompt = ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + f"{error_prompt_prefix}" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. A prioritized error diagnosis report: group recurring errors, map them to probable flow stages, " + "highlight missing metrics/log anomalies, and propose concrete debugging or mitigation actions.\n" + ) + elif stage == 'model': + prompt = ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + f"{error_prompt_prefix}" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + "5. Ways the model can help detect or avoid the diagnosed failure modes (e.g., additional features, " + "constraints, or uncertainty thresholds that flag risky configurations).\n" + ) + elif stage == 'agglomerate': + prompt = ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + f"{error_prompt_prefix}" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + "Also explain how each recommended parameter direction mitigates the recurring errors or failures identified above.\n" + ) + else: + prompt = ( + f"**Stage: {stage.capitalize()}**\n" + f"Data:\n{json.dumps(data, indent=2, default=str)}\n\n" + f"{error_prompt_prefix}" + "Please provide guidance based on the above data.\n" + ) + + print(f"[DEBUG] Prompt for stage={stage}:\n{prompt}\n") + return prompt + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + """Call Claude to get recommendations for optimization parameters""" + print(f"\n=== Calling LLM for {stage} stage ===") + + # Hardcode API key + # anthropic_api_key=" " + client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) + + tools = [ + { + "name": "configure_inspection", + "description": "Configure data inspection parameters", + "input_schema": { + "type": "object", + "properties": { + "n_clusters": { + "type": "integer", + "description": "Number of clusters for structure analysis", + "minimum": 2, + "maximum": 10 + }, + "correlation_threshold": { + "type": "number", + "description": "Threshold for considering correlations significant", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["n_clusters", "correlation_threshold"] + } + }, + { + "name": "configure_model", + "description": "Configure modeling approach", + "input_schema": { + "type": "object", + "properties": { + "kernel_type": { + "type": "string", + "enum": ["rbf", "matern", "rational"], + "description": "Type of kernel to use" + }, + "preprocessing": { + "type": "string", + "enum": ["standard", "robust", "none"], + "description": "Type of preprocessing to apply" + }, + "acquisition": { + "type": "string", + "enum": ["ei", "ucb", "pi"], + "description": "Acquisition function to use" + }, + "surrogate_weight": { + "type": "number", + "description": "Weight to give surrogate values", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] + } + }, + { + "name": "configure_selection", + "description": "Configure point selection strategy", + "input_schema": { + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["entropy", "kmeans", "hybrid", "graph"], + "description": "Selection method to use" + }, + "quality_weight": { + "type": "number", + "description": "Weight between quality and diversity", + "minimum": 0, + "maximum": 1 + }, + "uncertainty_bonus": { + "type": "number", + "description": "Weight for uncertainty in quality scores", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["method", "quality_weight", "uncertainty_bonus"] + } + } + ] + + # Get data summaries + if stage == 'inspect': + print("Generating data distribution and structure summaries...") + # Extract X and Y from successful runs if available + X = [] + Y = [] + if 'log_data' in data and 'runs' in data['log_data']: + for run in data['log_data']['runs']: + if run['success'] and 'metrics' in run: + obj = self._calculate_objective(run) + if obj['value'] is not None or obj['surrogate'] is not None: + # Use parameters as X + params = [] + for param in self.param_constraints.keys(): + params.append(float(run.get('parameters', {}).get(param, 0))) + X.append(params) + # Use objective as Y + Y.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + if X and Y: + dist_summary = inspect_data_distribution(np.array(X), np.array(Y)) + struct_summary = inspect_data_structure(np.array(X), np.array(Y)) + else: + print("No successful runs found, using empty summaries") + dist_summary = {} + struct_summary = {} + else: + dist_summary = {} + struct_summary = {} + + # Generate context message + context_message = self._generate_llm_prompt(stage, data) + print(f"[DEBUG] Context message for {stage}:\n{context_message}\n") + print(f"Generated prompt with context for {stage}") + + print("Making LLM API call...") + response = client.messages.create( + model="claude-sonnet-4-5", + max_tokens=2048, + tools=tools, + messages=[{ + "role": "user", + "content": context_message + }] + ) + + # Extract configurations + configs = {} + narrative_notes: List[str] = [] + print("\nReceived tool calls from LLM:") + for block in response.content: + if block.type == 'tool_use': + print(f"- {block.name}: {block.input}") + if block.name == 'configure_inspection': + configs['inspection'] = block.input + elif block.name == 'configure_model': + configs['model'] = block.input + elif block.name == 'configure_selection': + configs['selection'] = block.input + elif block.type == 'text': + # Capture any free-form reasoning so users can read root-cause analysis + note = getattr(block, 'text', '') + if note: + narrative_notes.append(note.strip()) + + if narrative_notes: + print("\nLLM diagnostic notes (non-tool response):") + for idx, note in enumerate(narrative_notes, start=1): + print(f"{idx}. {note}") + + # Add default configs if missing + for key, default in [ + ('inspection', {"n_clusters": 5, "correlation_threshold": 0.5}), + ('model', {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}), + ('selection', {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2}) + ]: + if key not in configs: + print(f"Warning: No {key} config from LLM, using defaults: {default}") + configs[key] = default + + return configs + + def run_iteration(self, num_runs: int) -> None: + """Run a complete iteration of the optimization workflow""" + print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + print(f"LLM inspection config: {inspect_configs['inspection']}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspect_configs['inspection']['n_clusters'], + correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results + print("\nGetting LLM recommendations for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + print(f"LLM model config: {model_configs['model']}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + kernel_type=model_configs['model']['kernel_type'], + preprocessing=model_configs['model']['preprocessing'], + acquisition=model_configs['model']['acquisition'], + surrogate_weight=model_configs['model']['surrogate_weight'] + ) + + # Get LLM recommendations for parameter selection based on all previous results + print("\nGetting LLM recommendations for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + print(f"LLM selection config: {selection_configs['selection']}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_configs['selection']['method'], + quality_weight=selection_configs['selection']['quality_weight'], + uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + ) + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + # case1:eg. logs/asap7_aes_run1.log + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + # case2:path includes base_* + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + # initialize run + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + # clustering + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + # def inspect_logs(self) -> Dict[str, Any]: + # """Step 1: Inspect all logs so far""" + # log_dir = f"logs/{self.platform}/{self.design}" + # log_data = { + # 'runs': [], + # 'summary': { + # 'total_runs': 0, + # 'successful_runs': 0, + # 'failed_runs': 0 + # } + # } + + # # Ensure log directory exists + # if not os.path.exists(log_dir): + # return log_data + + # # Process each log file + # for log_file in os.listdir(log_dir): + # if log_file.endswith('.log'): + # run_data = process_log_file(os.path.join(log_dir, log_file)) + # log_data['runs'].append(run_data) + + # # Update summary + # log_data['summary']['total_runs'] += 1 + # if run_data['success']: + # log_data['summary']['successful_runs'] += 1 + # else: + # log_data['summary']['failed_runs'] += 1 + + # return log_data + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) != 5: + print("Usage: optimize.py ") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + + workflow = OptimizationWorkflow(platform, design, objective) + workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps + +if __name__ == "__main__": + main() diff --git a/flow-Agent/comparison/optimize_orfs-agent_claude.py b/flow-Agent/comparison/optimize_orfs-agent_claude.py new file mode 100644 index 0000000..bd03d1d --- /dev/null +++ b/flow-Agent/comparison/optimize_orfs-agent_claude.py @@ -0,0 +1,1177 @@ +#!/usr/bin/env python3 + +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random + +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + + # Determine success based on completion markers and errors + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics +# def extract_timing_metrics(log_content: str) -> Dict[str, float]: +# """Extract timing-related metrics from log content""" +# metrics = {} + +# # Extract worst slack (final) +# slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if slack_match: +# metrics['worst_slack'] = float(slack_match.group(1)) + +# # Extract CTS worst slack +# cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if cts_slack_match: +# metrics['cts_ws'] = float(cts_slack_match.group(1)) + +# # Extract clock period +# period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) +# if period_match: +# metrics['clock_period'] = float(period_match.group(1)) + +# # Extract TNS +# tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) +# if tns_match: +# metrics['tns'] = float(tns_match.group(1)) + +# return metrics + +# def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: +# """Extract wirelength-related metrics from log content""" +# metrics = {} + +# # Extract total wirelength +# wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) +# if wl_match: +# metrics['total_wirelength'] = float(wl_match.group(1)) + +# # Extract estimated wirelength after CTS +# cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) +# if cts_wl_match: +# metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + +# return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str]) -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully', + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """Generate LLM prompt for different stages""" + + # Include parameter constraints in the prompt + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + # Construct the prompt based on the stage + if stage == 'inspect': + prompt = ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + ) + elif stage == 'model': + prompt = ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ) + elif stage == 'agglomerate': + prompt = ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + else: + prompt = ( + f"**Stage: {stage.capitalize()}**\n" + f"Data:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please provide guidance based on the above data. Please be sure to call the tool to return the structured configuration.\n" + ) + + return prompt + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + """Call Claude to get recommendations for optimization parameters""" + print(f"\n=== Calling LLM for {stage} stage ===") + + # Hardcode API key + # anthropic_api_key=" " + client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) + + tools = [ + { + "name": "configure_inspection", + "description": "Configure data inspection parameters", + "input_schema": { + "type": "object", + "properties": { + "n_clusters": { + "type": "integer", + "description": "Number of clusters for structure analysis", + "minimum": 2, + "maximum": 10 + }, + "correlation_threshold": { + "type": "number", + "description": "Threshold for considering correlations significant", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["n_clusters", "correlation_threshold"] + } + }, + { + "name": "configure_model", + "description": "Configure modeling approach", + "input_schema": { + "type": "object", + "properties": { + "kernel_type": { + "type": "string", + "enum": ["rbf", "matern", "rational"], + "description": "Type of kernel to use" + }, + "preprocessing": { + "type": "string", + "enum": ["standard", "robust", "none"], + "description": "Type of preprocessing to apply" + }, + "acquisition": { + "type": "string", + "enum": ["ei", "ucb", "pi"], + "description": "Acquisition function to use" + }, + "surrogate_weight": { + "type": "number", + "description": "Weight to give surrogate values", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] + } + }, + { + "name": "configure_selection", + "description": "Configure point selection strategy", + "input_schema": { + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["entropy", "kmeans", "hybrid", "graph"], + "description": "Selection method to use" + }, + "quality_weight": { + "type": "number", + "description": "Weight between quality and diversity", + "minimum": 0, + "maximum": 1 + }, + "uncertainty_bonus": { + "type": "number", + "description": "Weight for uncertainty in quality scores", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["method", "quality_weight", "uncertainty_bonus"] + } + } + ] + + # Get data summaries + if stage == 'inspect': + print("Generating data distribution and structure summaries...") + # Extract X and Y from successful runs if available + X = [] + Y = [] + if 'log_data' in data and 'runs' in data['log_data']: + for run in data['log_data']['runs']: + if run['success'] and 'metrics' in run: + obj = self._calculate_objective(run) + if obj['value'] is not None or obj['surrogate'] is not None: + # Use parameters as X + params = [] + for param in self.param_constraints.keys(): + params.append(float(run.get('parameters', {}).get(param, 0))) + X.append(params) + # Use objective as Y + Y.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + if X and Y: + dist_summary = inspect_data_distribution(np.array(X), np.array(Y)) + struct_summary = inspect_data_structure(np.array(X), np.array(Y)) + else: + print("No successful runs found, using empty summaries") + dist_summary = {} + struct_summary = {} + else: + dist_summary = {} + struct_summary = {} + + # Generate context message + context_message = self._generate_llm_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + + print("Making LLM API call...") + response = client.messages.create( + model="claude-sonnet-4-5", + # max_tokens=2048, + max_tokens=4096, + tools=tools, + messages=[{ + "role": "user", + "content": context_message + }] + ) + + # Extract configurations + configs = {} + print("\nReceived tool calls from LLM:") + for block in response.content: + if block.type == 'tool_use': + print(f"- {block.name}: {block.input}") + if block.name == 'configure_inspection': + configs['inspection'] = block.input + elif block.name == 'configure_model': + configs['model'] = block.input + elif block.name == 'configure_selection': + configs['selection'] = block.input + elif block.type == 'text': + print(f"LLM text reply: {block.text}") + + # Add default configs if missing + for key, default in [ + ('inspection', {"n_clusters": 5, "correlation_threshold": 0.5}), + ('model', {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}), + ('selection', {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2}) + ]: + if key not in configs: + print(f"Warning: No {key} config from LLM, using defaults: {default}") + configs[key] = default + + return configs + + def run_iteration(self, num_runs: int) -> None: + """Run a complete iteration of the optimization workflow""" + print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + print(f"LLM inspection config: {inspect_configs['inspection']}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspect_configs['inspection']['n_clusters'], + correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results + print("\nGetting LLM recommendations for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + print(f"LLM model config: {model_configs['model']}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + kernel_type=model_configs['model']['kernel_type'], + preprocessing=model_configs['model']['preprocessing'], + acquisition=model_configs['model']['acquisition'], + surrogate_weight=model_configs['model']['surrogate_weight'] + ) + + # Get LLM recommendations for parameter selection based on all previous results + print("\nGetting LLM recommendations for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + print(f"LLM selection config: {selection_configs['selection']}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_configs['selection']['method'], + quality_weight=selection_configs['selection']['quality_weight'], + uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + ) + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + # case1:eg. logs/asap7_aes_run1.log + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + # case2:path includes base_* + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + # initialize run + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + # clustering + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + # def inspect_logs(self) -> Dict[str, Any]: + # """Step 1: Inspect all logs so far""" + # log_dir = f"logs/{self.platform}/{self.design}" + # log_data = { + # 'runs': [], + # 'summary': { + # 'total_runs': 0, + # 'successful_runs': 0, + # 'failed_runs': 0 + # } + # } + + # # Ensure log directory exists + # if not os.path.exists(log_dir): + # return log_data + + # # Process each log file + # for log_file in os.listdir(log_dir): + # if log_file.endswith('.log'): + # run_data = process_log_file(os.path.join(log_dir, log_file)) + # log_data['runs'].append(run_data) + + # # Update summary + # log_data['summary']['total_runs'] += 1 + # if run_data['success']: + # log_data['summary']['successful_runs'] += 1 + # else: + # log_data['summary']['failed_runs'] += 1 + + # return log_data + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) != 5: + print("Usage: optimize.py ") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + + workflow = OptimizationWorkflow(platform, design, objective) + workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps + +if __name__ == "__main__": + main() diff --git a/flow-Agent/comparison/optimize_orfs-agent_deepseek.py b/flow-Agent/comparison/optimize_orfs-agent_deepseek.py new file mode 100644 index 0000000..b387eda --- /dev/null +++ b/flow-Agent/comparison/optimize_orfs-agent_deepseek.py @@ -0,0 +1,1205 @@ +#!/usr/bin/env python3 + +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +# import anthropic +import csv +import random +# from rag.util import answerWithRAG +# from rag.index import load_embeddings_and_docs, build_and_save_embeddings +import torch +from sentence_transformers import SentenceTransformer +from pathlib import Path + +from openai import OpenAI +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + print(f"File size: {len(content)} characters") + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + + # Determine success based on completion markers and errors + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str]) -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully' + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + # emb_np, docs, docsDict = load_embeddings_and_docs() + # self.rag_embeddings = torch.tensor(emb_np).cpu() + # self.rag_docs = docs + # self.rag_docsDict = docsDict + # print("[INFO] Loading embedding model...") + # model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + # model_path = model_path.resolve() + # self.rag_model = SentenceTransformer(str(model_path)) + + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + tool_instructions = { + 'inspect': ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ), + + 'agglomerate': ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + } + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** + + {stage_contexts.get(stage, '')} + + {tool_instructions.get(stage, '')} + + **Important: Use **tool calls only**, and generate text responses!** + """ + # ========= 拼接 RAG ========= + # rag_context = "" + # if self.rag_model is not None and self.rag_embeddings is not None: + # try: + # print("[DEBUG] RAG: Starting retrieval...") + # query = ( + # f"Stage: {stage}. Objective: {self.objective}. " + # f"Focus on analyzing {stage}-related optimization results. " + # f"Important metrics include wirelength, timing, area, and success rate. " + # f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + # ) + # rag_context = answerWithRAG( + # query, + # self.rag_embeddings, + # self.rag_model, + # self.rag_docs, + # self.rag_docsDict + # ) + # print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + # if rag_context.strip(): + # prompt += ( + # "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + # f"{rag_context}\n" + # "==============================================" + # ) + # print("[DEBUG] RAG: Context successfully added to prompt.") + # else: + # print("[DEBUG] RAG: Empty context retrieved.") + # except Exception as e: + # prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + return prompt + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + """Call Claude to get recommendations for optimization parameters""" + print(f"\n=== Calling LLM for {stage} stage ===") + + # Hardcode API key + # api_key = ""#PUT YOUR KEY HERE + + # client = anthropic.Anthropic(api_key=api_key) + client = OpenAI( + base_url="https://ai.gitee.com/v1", + api_key=" ", + ) + + tools = [ + { + "type": "function", + "function": { + "name": "configure_inspection", + "description": "Configure data inspection parameters", + "parameters": { + "type": "object", + "properties": { + "n_clusters": { + "type": "integer", + "description": "Number of clusters for structure analysis", + "minimum": 2, + "maximum": 10 + }, + "correlation_threshold": { + "type": "number", + "description": "Threshold for considering correlations significant", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["n_clusters", "correlation_threshold"] + } + } + }, + { + "type": "function", + "function": { + "name": "configure_model", + "description": "Configure modeling approach", + "parameters": { + "type": "object", + "properties": { + "kernel_type": { + "type": "string", + "enum": ["rbf", "matern", "rational"], + "description": "Type of kernel to use" + }, + "preprocessing": { + "type": "string", + "enum": ["standard", "robust", "none"], + "description": "Type of preprocessing to apply" + }, + "acquisition": { + "type": "string", + "enum": ["ei", "ucb", "pi"], + "description": "Acquisition function to use" + }, + "surrogate_weight": { + "type": "number", + "description": "Weight to give surrogate values", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] + } + } + }, + { + "type": "function", + "function": { + "name": "configure_selection", + "description": "Configure point selection strategy", + "parameters": { + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["entropy", "kmeans", "hybrid", "graph"], + "description": "Selection method to use" + }, + "quality_weight": { + "type": "number", + "description": "Weight between quality and diversity", + "minimum": 0, + "maximum": 1 + }, + "uncertainty_bonus": { + "type": "number", + "description": "Weight for uncertainty in quality scores", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["method", "quality_weight", "uncertainty_bonus"] + } + } + } + ] + + # Get data summaries + if stage == 'inspect': + print("Generating data distribution and structure summaries...") + # Extract X and Y from successful runs if available + print("=== DEBUG: Checking data structure ===") + print(f"data keys: {list(data.keys()) if data else 'Empty data'}") + X = [] + Y = [] + if 'log_data' in data and 'runs' in data['log_data']: + print("✓ 'log_data' and 'runs' found in data") + print(f"Number of runs: {len(data['log_data']['runs'])}") + for run in data['log_data']['runs']: + if run['success'] and 'metrics' in run: + obj = self._calculate_objective(run) + if obj['value'] is not None or obj['surrogate'] is not None: + # Use parameters as X + params = [] + for param in self.param_constraints.keys(): + params.append(float(run.get('parameters', {}).get(param, 0))) + X.append(params) + # Use objective as Y + Y.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + print(f" ✓ Added to X and Y: X={params}, Y={obj['value'] if obj['value'] is not None else obj['surrogate']}") + + if X and Y: + dist_summary = inspect_data_distribution(np.array(X), np.array(Y)) + # struct_summary = inspect_data_structure(np.array(X)) + struct_summary = inspect_data_structure(np.array(X), np.array(Y)) + print("dist_summary =", dist_summary) + print("struct_summary =", struct_summary) + print("DEBUG: len(X)=", len(X), " len(Y)=", len(Y)) + else: + print("No successful runs found, using empty summaries") + dist_summary = {} + struct_summary = {} + else: + dist_summary = {} + struct_summary = {} + + # Generate context message + context_message = self._generate_llm_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(context_message) + print("========================") + + print("Making LLM API call...") + # response = client.messages.create( + response = client.chat.completions.create( + # model="claude-3-sonnet-20240229", + model="DeepSeek-V3", + messages=[{ + "role": "user", + "content": context_message + }], + # max_tokens=2048, + tools=tools, + tool_choice="auto", + # stream=True, + max_tokens=1024, + temperature=0.1, + timeout=300.0, + ) + + # Extract configurations + configs = {} + print("=== Complete API response ===") + print(f"Response type: {type(response)}") + print(f"Choices count: {len(response.choices)}") + print("\nReceived tool calls from LLM:") + message = response.choices[0].message + print(f"Message content: {getattr(message, 'content', 'No content')}") + print(f"Tool calls: {getattr(message, 'tool_calls', 'No tool calls')}") + + # Check if any tools are being called + if hasattr(message, 'tool_calls') and message.tool_calls: + for tool_call in message.tool_calls: + function_name = tool_call.function.name + function_args = json.loads(tool_call.function.arguments) + + print(f"- {function_name}: {function_args}") + + if function_name == 'configure_inspection': + configs['inspection'] = function_args + elif function_name == 'configure_model': + configs['model'] = function_args + elif function_name == 'configure_selection': + configs['selection'] = function_args + + # Add default configs if missing + for key, default in [ + ('inspection', {"n_clusters": 5, "correlation_threshold": 0.5}), + ('model', {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}), + ('selection', {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2}) + ]: + if key not in configs: + print(f"Warning: No {key} config from LLM, using defaults: {default}") + configs[key] = default + + return configs + + def run_iteration(self, num_runs: int) -> None: + """Run a complete iteration of the optimization workflow""" + print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + print(f"LLM inspection config: {inspect_configs['inspection']}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspect_configs['inspection']['n_clusters'], + correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results + print("\nGetting LLM recommendations for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + print(f"LLM model config: {model_configs['model']}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + kernel_type=model_configs['model']['kernel_type'], + preprocessing=model_configs['model']['preprocessing'], + acquisition=model_configs['model']['acquisition'], + surrogate_weight=model_configs['model']['surrogate_weight'] + ) + + # Get LLM recommendations for parameter selection based on all previous results + print("\nGetting LLM recommendations for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + print(f"LLM selection config: {selection_configs['selection']}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_configs['selection']['method'], + quality_weight=selection_configs['selection']['quality_weight'], + uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + ) + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + # case1:eg. logs/asap7_aes_run1.log + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + # case2:path includes base_* + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + # initialize run + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + # clustering + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) != 5: + print("Usage: optimize.py ") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + + workflow = OptimizationWorkflow(platform, design, objective) + workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps + +if __name__ == "__main__": + main() diff --git a/flow-Agent/comparison/optimize_rag_only.py b/flow-Agent/comparison/optimize_rag_only.py new file mode 100644 index 0000000..0a650d5 --- /dev/null +++ b/flow-Agent/comparison/optimize_rag_only.py @@ -0,0 +1,1460 @@ +#!/usr/bin/env python3 + +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random +from rag.util import answerWithRAG +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from sentence_transformers import SentenceTransformer +import torch +from pathlib import Path + +from openai import OpenAI +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + print(f"File size: {len(content)} characters") + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + + # Determine success based on completion markers and errors + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str]) -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully' + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + emb_np, docs, docsDict = load_embeddings_and_docs() + self.rag_embeddings = torch.tensor(emb_np).cpu() + self.rag_docs = docs + self.rag_docsDict = docsDict + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + model_path = model_path.resolve() + self.rag_model = SentenceTransformer(str(model_path)) + + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + # def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + # """Generate LLM prompt for different stages""" + + # # Include parameter constraints in the prompt + # constraints_text = "Parameter Constraints:\n" + # for param, info in self.param_constraints.items(): + # param_type = info['type'] + # param_range = info['range'] + # constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + # # Construct the prompt based on the stage + # if stage == 'inspect': + # prompt = ( + # f"**Stage: Inspect**\n" + # "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + # # f"Data to analyze:\n{json.dumps(data, indent=2)}\n\n" + # f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + # "Please analyze the data and provide insights on:\n" + # "1. Key patterns in successful vs unsuccessful runs.\n" + # "2. Parameter ranges that appear promising.\n" + # "3. Any timing or wirelength trends.\n" + # "4. Recommendations for subsequent runs.\n" + # ) + # elif stage == 'model': + # prompt = ( + # f"**Stage: Model**\n" + # "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + # # f"Data for modeling:\n{json.dumps(data, indent=2)}\n\n" + # f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + # "Please suggest:\n" + # "1. Appropriate modeling techniques.\n" + # "2. Key parameters to focus on.\n" + # "3. Surrogate model recommendations.\n" + # "4. Acquisition function choices.\n" + # ) + # elif stage == 'agglomerate': + # prompt = ( + # f"**Stage: Agglomerate**\n" + # "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + # "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + # f"{constraints_text}\n" + # "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + # "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + # ) + # else: + # prompt = ( + # f"**Stage: {stage.capitalize()}**\n" + # # f"Data:\n{json.dumps(data, indent=2)}\n\n" + # f"Data:\n{json.dumps(data, indent=2, default=str)}\n\n" + # "Please provide guidance based on the above data.\n" + # ) + + # return prompt + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + tool_instructions = { + 'inspect': ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ), + + 'agglomerate': ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + } + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** + + {stage_contexts.get(stage, '')} + + {tool_instructions.get(stage, '')} + + **Important: Use **tool calls only**, and generate text responses!** + """ + # ========= 拼接 RAG ========= + rag_context = "" + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict + ) + print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + if rag_context.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{rag_context}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + return prompt + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + """Call Claude to get recommendations for optimization parameters""" + print(f"\n=== Calling LLM for {stage} stage ===") + + # Hardcode API key + # api_key = ""#PUT YOUR KEY HERE + + # client = anthropic.Anthropic(api_key=api_key) + client = OpenAI( + base_url="https://ai.gitee.com/v1", + api_key=""#PUT YOUR KEY HERE, + ) + + tools = [ + { + "type": "function", + "function": { + "name": "configure_inspection", + "description": "Configure data inspection parameters", + "parameters": { + "type": "object", + "properties": { + "n_clusters": { + "type": "integer", + "description": "Number of clusters for structure analysis", + "minimum": 2, + "maximum": 10 + }, + "correlation_threshold": { + "type": "number", + "description": "Threshold for considering correlations significant", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["n_clusters", "correlation_threshold"] + } + } + }, + { + "type": "function", + "function": { + "name": "configure_model", + "description": "Configure modeling approach", + "parameters": { + "type": "object", + "properties": { + "kernel_type": { + "type": "string", + "enum": ["rbf", "matern", "rational"], + "description": "Type of kernel to use" + }, + "preprocessing": { + "type": "string", + "enum": ["standard", "robust", "none"], + "description": "Type of preprocessing to apply" + }, + "acquisition": { + "type": "string", + "enum": ["ei", "ucb", "pi"], + "description": "Acquisition function to use" + }, + "surrogate_weight": { + "type": "number", + "description": "Weight to give surrogate values", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] + } + } + }, + { + "type": "function", + "function": { + "name": "configure_selection", + "description": "Configure point selection strategy", + "parameters": { + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["entropy", "kmeans", "hybrid", "graph"], + "description": "Selection method to use" + }, + "quality_weight": { + "type": "number", + "description": "Weight between quality and diversity", + "minimum": 0, + "maximum": 1 + }, + "uncertainty_bonus": { + "type": "number", + "description": "Weight for uncertainty in quality scores", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["method", "quality_weight", "uncertainty_bonus"] + } + } + } + ] + + # tools = [ + # { + # "name": "configure_inspection", + # "description": "Configure data inspection parameters", + # "input_schema": { + # "type": "object", + # "properties": { + # "n_clusters": { + # "type": "integer", + # "description": "Number of clusters for structure analysis", + # "minimum": 2, + # "maximum": 10 + # }, + # "correlation_threshold": { + # "type": "number", + # "description": "Threshold for considering correlations significant", + # "minimum": 0, + # "maximum": 1 + # } + # }, + # "required": ["n_clusters", "correlation_threshold"] + # } + # }, + # { + # "name": "configure_model", + # "description": "Configure modeling approach", + # "input_schema": { + # "type": "object", + # "properties": { + # "kernel_type": { + # "type": "string", + # "enum": ["rbf", "matern", "rational"], + # "description": "Type of kernel to use" + # }, + # "preprocessing": { + # "type": "string", + # "enum": ["standard", "robust", "none"], + # "description": "Type of preprocessing to apply" + # }, + # "acquisition": { + # "type": "string", + # "enum": ["ei", "ucb", "pi"], + # "description": "Acquisition function to use" + # }, + # "surrogate_weight": { + # "type": "number", + # "description": "Weight to give surrogate values", + # "minimum": 0, + # "maximum": 1 + # } + # }, + # "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] + # } + # }, + # { + # "name": "configure_selection", + # "description": "Configure point selection strategy", + # "input_schema": { + # "type": "object", + # "properties": { + # "method": { + # "type": "string", + # "enum": ["entropy", "kmeans", "hybrid", "graph"], + # "description": "Selection method to use" + # }, + # "quality_weight": { + # "type": "number", + # "description": "Weight between quality and diversity", + # "minimum": 0, + # "maximum": 1 + # }, + # "uncertainty_bonus": { + # "type": "number", + # "description": "Weight for uncertainty in quality scores", + # "minimum": 0, + # "maximum": 1 + # } + # }, + # "required": ["method", "quality_weight", "uncertainty_bonus"] + # } + # } + # ] + + # Get data summaries + if stage == 'inspect': + print("Generating data distribution and structure summaries...") + # Extract X and Y from successful runs if available + print("=== DEBUG: Checking data structure ===") + print(f"data keys: {list(data.keys()) if data else 'Empty data'}") + X = [] + Y = [] + if 'log_data' in data and 'runs' in data['log_data']: + print("✓ 'log_data' and 'runs' found in data") + print(f"Number of runs: {len(data['log_data']['runs'])}") + for run in data['log_data']['runs']: + if run['success'] and 'metrics' in run: + obj = self._calculate_objective(run) + if obj['value'] is not None or obj['surrogate'] is not None: + # Use parameters as X + params = [] + for param in self.param_constraints.keys(): + params.append(float(run.get('parameters', {}).get(param, 0))) + X.append(params) + # Use objective as Y + Y.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + print(f" ✓ Added to X and Y: X={params}, Y={obj['value'] if obj['value'] is not None else obj['surrogate']}") + + if X and Y: + dist_summary = inspect_data_distribution(np.array(X), np.array(Y)) + # struct_summary = inspect_data_structure(np.array(X)) + struct_summary = inspect_data_structure(np.array(X), np.array(Y)) + print("dist_summary =", dist_summary) + print("struct_summary =", struct_summary) + print("DEBUG: len(X)=", len(X), " len(Y)=", len(Y)) + else: + print("No successful runs found, using empty summaries") + dist_summary = {} + struct_summary = {} + else: + dist_summary = {} + struct_summary = {} + + # Generate context message + context_message = self._generate_llm_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(context_message) + print("========================") + + print("Making LLM API call...") + # response = client.messages.create( + response = client.chat.completions.create( + # model="claude-3-sonnet-20240229", + model="DeepSeek-V3", + messages=[{ + "role": "user", + "content": context_message + }], + # max_tokens=2048, + tools=tools, + tool_choice="auto", + # stream=True, + max_tokens=1024, + temperature=0.1, + # top_p=0.8, + # extra_body={ + # "top_k": 20, + # }, + # frequency_penalty=1.1, + + # messages=[{ + # "role": "user", + # "content": context_message + # }] + ) + + # Extract configurations + configs = {} + print("=== 完整API响应 ===") + print(f"Response type: {type(response)}") + print(f"Choices count: {len(response.choices)}") + print("\nReceived tool calls from LLM:") + message = response.choices[0].message + print(f"Message content: {getattr(message, 'content', 'No content')}") + print(f"Tool calls: {getattr(message, 'tool_calls', 'No tool calls')}") + + # 检查是否有工具调用 + if hasattr(message, 'tool_calls') and message.tool_calls: + for tool_call in message.tool_calls: + function_name = tool_call.function.name + function_args = json.loads(tool_call.function.arguments) + + print(f"- {function_name}: {function_args}") + + if function_name == 'configure_inspection': + configs['inspection'] = function_args + elif function_name == 'configure_model': + configs['model'] = function_args + elif function_name == 'configure_selection': + configs['selection'] = function_args + + # for block in response.content: + # if block.type == 'tool_use': + # print(f"- {block.name}: {block.input}") + # if block.name == 'configure_inspection': + # configs['inspection'] = block.input + # elif block.name == 'configure_model': + # configs['model'] = block.input + # elif block.name == 'configure_selection': + # configs['selection'] = block.input + + # Add default configs if missing + for key, default in [ + ('inspection', {"n_clusters": 5, "correlation_threshold": 0.5}), + ('model', {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}), + ('selection', {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2}) + ]: + if key not in configs: + print(f"Warning: No {key} config from LLM, using defaults: {default}") + configs[key] = default + + return configs + + def run_iteration(self, num_runs: int) -> None: + """Run a complete iteration of the optimization workflow""" + print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + print(f"LLM inspection config: {inspect_configs['inspection']}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspect_configs['inspection']['n_clusters'], + correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results + print("\nGetting LLM recommendations for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + print(f"LLM model config: {model_configs['model']}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + kernel_type=model_configs['model']['kernel_type'], + preprocessing=model_configs['model']['preprocessing'], + acquisition=model_configs['model']['acquisition'], + surrogate_weight=model_configs['model']['surrogate_weight'] + ) + + # Get LLM recommendations for parameter selection based on all previous results + print("\nGetting LLM recommendations for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + print(f"LLM selection config: {selection_configs['selection']}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_configs['selection']['method'], + quality_weight=selection_configs['selection']['quality_weight'], + uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + ) + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + # 匹配主日志或子目录日志 + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + # ---- 提取 run_id ---- + run_id = "main" # 默认 + # 情况1:主日志,例如 logs/asap7_aes_run1.log + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + # 情况2:路径中包含 base_* + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + # 初始化 run 组 + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + # 聚合 + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + # def inspect_logs(self) -> Dict[str, Any]: + # """Step 1: Inspect all logs so far""" + # # log_dir = f"logs/{self.platform}/{self.design}" + # log_dir = "logs" + # pattern = f"{self.platform}_{self.design}_run" + # log_data = { + # 'runs': [], + # 'summary': { + # 'total_runs': 0, + # 'successful_runs': 0, + # 'failed_runs': 0 + # } + # } + + # # Ensure log directory exists + # if not os.path.exists(log_dir): + # return log_data + + # # Process each log file + # for log_file in os.listdir(log_dir): + # # if log_file.endswith('.log'): + # if log_file.endswith('.log') and log_file.startswith(pattern): + # run_data = process_log_file(os.path.join(log_dir, log_file)) + # print(f"DEBUG: Run success: {run_data['success']}") + # print(f"DEBUG: Run metrics: {run_data['metrics']}") + # print(f"DEBUG: Run errors: {run_data['errors']}") + # log_data['runs'].append(run_data) + + # # Update summary + # log_data['summary']['total_runs'] += 1 + # if run_data['success']: + # log_data['summary']['successful_runs'] += 1 + # else: + # log_data['summary']['failed_runs'] += 1 + + # return log_data + # def inspect_logs(self) -> Dict[str, Any]: + # """Step 1: Inspect all logs so far""" + # log_dir = f"logs/{self.platform}/{self.design}" + # log_data = { + # 'runs': [], + # 'summary': { + # 'total_runs': 0, + # 'successful_runs': 0, + # 'failed_runs': 0 + # } + # } + + # # Ensure log directory exists + # if not os.path.exists(log_dir): + # return log_data + + # # Process each log file + # for log_file in os.listdir(log_dir): + # if log_file.endswith('.log'): + # run_data = process_log_file(os.path.join(log_dir, log_file)) + # log_data['runs'].append(run_data) + + # # Update summary + # log_data['summary']['total_runs'] += 1 + # if run_data['success']: + # log_data['summary']['successful_runs'] += 1 + # else: + # log_data['summary']['failed_runs'] += 1 + + # return log_data + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + # def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + # kernel_type: str, preprocessing: str, aciquisition: str, surrogate_weight: float) -> Dict[str, Any]: + # """Step 3: Use improved model functions to evaluate parameter quality""" + # model_results = {} + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) != 5: + print("Usage: optimize.py ") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + + workflow = OptimizationWorkflow(platform, design, objective) + workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps + +# def main(): +# if len(sys.argv) != 6: +# print("Usage: optimize.py ") +# sys.exit(1) + +# platform = sys.argv[1] +# design = sys.argv[2] +# objective = sys.argv[3] +# num_runs = int(sys.argv[4]) +# num_iterations = int(sys.argv[5]) # 添加迭代次数参数 + +# workflow = OptimizationWorkflow(platform, design, objective) + +# for iteration in range(num_iterations): +# print(f"\n{'='*50}") +# print(f"Starting Optimization Iteration {iteration + 1}/{num_iterations}") +# print(f"{'='*50}") + +# workflow.run_iteration(num_runs) + +# # 等待新参数运行完成(需要实际部署运行) +# # wait_for_runs_completion() + +# print(f"Completed Iteration {iteration + 1}") + +if __name__ == "__main__": + main() diff --git a/flow-Agent/comparison/optimize_react_only.py b/flow-Agent/comparison/optimize_react_only.py new file mode 100644 index 0000000..b09a8d8 --- /dev/null +++ b/flow-Agent/comparison/optimize_react_only.py @@ -0,0 +1,2499 @@ +#!/usr/bin/env python3 +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random +from rag.util import answerWithRAG +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from sentence_transformers import SentenceTransformer +import torch +from pathlib import Path +from openai import OpenAI +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * +import warnings +warnings.filterwarnings("ignore", category=RuntimeWarning) + +print("Python executable:", sys.executable) +print("sys.path:", sys.path[:3]) +print("Current working dir:", os.getcwd()) + +for pkg in ["anthropic", "sentence_transformers", "torch", "openai"]: + try: + __import__(pkg) + print(f" Imported {pkg}") + except ImportError as e: + print(f" Failed to import {pkg}: {e}") + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + print(f"File size: {len(content)} characters") + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + # === Inject a simulated error for testing RAG debugging === + # if "run3" in log_path: # 👈 你可以换成任意 run,比如 run1 或 run2 + # fake_error = "[ERROR] TEST_SIM: Simulated routing congestion failure" + # print(f"[DEBUG] Injected simulated error in {log_path}: {fake_error}") + # run_data['errors'].append(fake_error) + # run_data['success'] = False + + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str], filename: str = "") -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + # If any real error lines were found, this file is a failure indicator + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully' + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + + +class ReActFramework: + """ReAct framework implementation""" + + def __init__(self, client, model_name="DeepSeek-V3"): + self.client = client + self.model_name = model_name + self.conversation_history = [] + + def add_to_history(self, role: str, content: str): + """add conversation history""" + self.conversation_history.append({"role": role, "content": content}) + + def clear_history(self): + """clear conversation history""" + self.conversation_history = [] + + def extract_thought_action(self, response: str) -> Tuple[str, str, str]: + """ + Extract Thought, Action, and Action Input from LLM responses + Format: Thought:... Action:... Action Input: ... + """ + thought = "" + action = "" + action_input = "" + + # Extract Thought + thought_match = re.search(r'Thought:\s*(.*?)(?=\nAction:|$)', response, re.DOTALL) + if thought_match: + thought = thought_match.group(1).strip() + + # Extract Action + action_match = re.search(r'Action:\s*(\w+)', response) + if action_match: + action = action_match.group(1).strip() + + # Extract Action Input + action_input_match = re.search(r'Action Input:\s*(.*?)(?=\nObservation:|$)', response, re.DOTALL) + if action_input_match: + action_input = action_input_match.group(1).strip() + # Try to parse JSON + try: + if action_input.startswith('{') or action_input.startswith('['): + action_input = json.loads(action_input) + except: + pass # Maintain the string format + + if "Final Answer:" in response and ("Action:" in response or "Observation:" in response): + + response = response.split("Final Answer:")[0] + print("Removed premature Final Answer from response") + + return thought, action, action_input + + def execute_action(self, action: str, action_input: Any, available_tools: Dict) -> str: + """Execute tool call and return observation results""" + if action in available_tools: + try: + result = available_tools[action](action_input) + return f"Action executed successfully. Result: {result}" + except Exception as e: + return f"Action execution failed: {str(e)}" + else: + return f"Unknown action: {action}. Available actions: {list(available_tools.keys())}" + + def run_react_cycle(self, + initial_prompt: str, + available_tools: Dict, + max_steps: int = 5, + temperature: float = 0.1) -> Dict[str, Any]: + """ + Run ReAct loop + + Args: + initial_prompt: Initial prompt + available_tools: Available tool function dictionary + max_steps: Maximum reasoning steps + temperature: temperature parameter + + Returns: + a dictionary containing the final result and the reasoning history + """ + self.clear_history() + self.add_to_history("user", initial_prompt) + + history = [] + final_answer = None + completed_steps = 0 + + for step in range(max_steps): + print(f"\n=== ReAct Step {step + 1}/{max_steps} ===") + completed_steps = step + 1 + + # Call LLM to obtain response + try: + response = self.client.chat.completions.create( + model=self.model_name, + messages=self.conversation_history, + temperature=temperature, + max_tokens=1024 + ) + + llm_response = response.choices[0].message.content + print(f"LLM Response: {llm_response}") + except Exception as e: + print(f"Error calling LLM: {e}") + llm_response = f"Error in LLM call: {e}" + + # Extract Thought, Action, Action Input + thought, action, action_input = self.extract_thought_action(llm_response) + + step_data = { + "step": step + 1, + "thought": thought, + "action": action, + "action_input": action_input, + "llm_response": llm_response + } + + # Check if it is the final answer + final_answer_detected = False + if "Final Answer:" in llm_response: + final_answer_match = re.search(r'Final Answer:\s*(.*?)$', llm_response, re.DOTALL) + if final_answer_match: + final_answer = final_answer_match.group(1).strip() + step_data["final_answer"] = final_answer + final_answer_detected = True + print(f"✓ Final answer detected at step {step + 1}") + + observation = "" + # Execute actions and obtain observation results + if action and not final_answer_detected: + observation = self.execute_action(action, action_input, available_tools) + step_data["observation"] = observation + + # Update conversation history + self.add_to_history("assistant", llm_response) + self.add_to_history("user", f"Observation: {observation}") + + print(f"Thought: {thought}") + print(f"Action: {action}") + print(f"Action Input: {action_input}") + print(f"Observation: {observation}") + else: + if not final_answer_detected: + # If there is no clear action, it may be during the reasoning process + self.add_to_history("assistant", llm_response) + step_data["observation"] = "No action taken - continuing reasoning" + observation = "No action taken" + else: + # If it is the final answer, no further action is required + step_data["observation"] = "Final answer provided - cycle complete" + observation = "Final answer provided" + + history.append(step_data) + + if final_answer_detected: + print(f" ReAct cycle completed at step {step + 1} with final answer") + break + + # Check if it should end early + if step >= max_steps - 1: + final_answer = f"Reached maximum steps ({max_steps}) without final answer" + print(f" Reached maximum steps without final answer") + break + + if final_answer is None: + final_answer = "No final answer produced" + + return { + "final_answer": final_answer, + "reasoning_history": history, + "success": final_answer is not None and "Reached maximum steps" not in final_answer and "No final answer" not in final_answer, + "completed_steps": completed_steps, + "max_steps": max_steps + } + + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + emb_np, docs, docsDict = load_embeddings_and_docs() + self.rag_embeddings = torch.tensor(emb_np).cpu() + self.rag_docs = docs + self.rag_docsDict = docsDict + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + model_path = model_path.resolve() + # self.rag_model = SentenceTransformer(str(model_path)) + self.rag_model = SentenceTransformer(str(model_path), device='cpu') + + self.react_framework = ReActFramework( + client=OpenAI( + base_url="https://ai.gitee.com/v1", + # api_key=" ", + api_key=" ", + ), + model_name="DeepSeek-V3" + ) + + def _create_react_tools(self, stage: str, data: Dict[str, Any]) -> Dict: + """Create available utility functions for different stages""" + + base_tools = { + "analyze_data_distribution": lambda x: self._call_existing_distribution_analysis(data), + "analyze_data_structure": lambda x: self._call_existing_structure_analysis(data), + "evaluate_parameter_ranges": lambda x: self._evaluate_parameter_ranges(data), + "check_constraints": lambda x: self._check_constraints_compliance(data), + "suggest_improvements": lambda x: self._suggest_improvements(stage, data), + } + + if stage == 'inspect': + inspection_tools = { + "configure_inspection": lambda config: self._configure_inspection_with_existing(config, data), + "analyze_correlations": lambda params: self._analyze_correlations_with_existing(params, data), + "cluster_analysis": lambda config: self._cluster_analysis_with_existing(config, data), + "manifold_analysis": lambda config: self._manifold_analysis_with_existing(config, data), + "local_structure_analysis": lambda config: self._local_structure_analysis_with_existing(config, data), + } + base_tools.update(inspection_tools) + + elif stage == 'model': + modeling_tools = { + "configure_model": lambda config: self._configure_model_with_existing(config, data), + "evaluate_surrogate": lambda params: self._evaluate_surrogate_with_existing(params, data), + "select_acquisition": lambda method: self._select_acquisition_with_existing(method, data), + "create_surrogate_model": lambda config: self._create_surrogate_model_with_existing(config, data), + "evaluate_timing_model": lambda x: self._evaluate_timing_model_with_existing(data), + "evaluate_wirelength_model": lambda x: self._evaluate_wirelength_model_with_existing(data), + "get_model_recommendations": lambda x: self._get_model_recommendations_from_existing(data), + } + base_tools.update(modeling_tools) + + elif stage == 'agglomerate': + selection_tools = { + "configure_selection": lambda config: self._configure_selection_with_existing(config, data), + "generate_parameters": lambda count: self._generate_parameters_with_existing(count, data), + "validate_parameters": lambda params: self._validate_parameters_tool(params), + "latin_hypercube_sampling": lambda config: self._latin_hypercube_sampling_with_existing(config, data), + "create_quality_scores": lambda config: self._create_quality_scores_with_existing(config, data), + "select_points": lambda config: self._select_points_with_existing(config, data), + "compare_selection_methods": lambda config: self._compare_selection_methods_with_existing(config, data), + "kmeans_selection": lambda config: self._kmeans_selection_with_existing(config, data), + "hybrid_selection": lambda config: self._hybrid_selection_with_existing(config, data), + "entropy_selection": lambda config: self._entropy_selection_with_existing(config, data), + "graph_selection": lambda config: self._graph_selection_with_existing(config, data), + } + base_tools.update(selection_tools) + + return base_tools + + + def _call_existing_distribution_analysis(self, data: Dict) -> str: + """Call existing data distribution analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_distribution(X, Y) + return self._format_analysis_result("Data Distribution Analysis", result) + else: + return "Insufficient data for distribution analysis" + + except Exception as e: + return f"Error in distribution analysis: {str(e)}" + + def _call_existing_structure_analysis(self, data: Dict) -> str: + """Call existing data structure analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Use default configuration or retrieve configuration from data + config = { + "n_clusters": 5, + "correlation_threshold": 0.5, + "n_neighbors": 20, + "perplexity": 30 + } + + result = inspect_data_structure(X, Y, config) + return self._format_analysis_result("Data Structure Analysis", result) + else: + return "Insufficient data for structure analysis" + + except Exception as e: + return f"Error in structure analysis: {str(e)}" + + def _evaluate_parameter_ranges(self, data: Dict) -> str: + """Evaluation Parameter Range Tool - Implementation""" + constraints_info = "Parameter Constraints Evaluation:\n" + + # Analyze the current usage of parameters + param_usage = {} + for run in data.get('log_data', {}).get('runs', []): + if run.get('parameters'): + for param, value in run['parameters'].items(): + if param not in param_usage: + param_usage[param] = [] + param_usage[param].append(float(value)) + + for param, info in self.param_constraints.items(): + min_val, max_val = info['range'] + param_type = info['type'] + + constraints_info += f"\n- {param} ({param_type}): range [{min_val}, {max_val}]" + + if param in param_usage: + values = param_usage[param] + used_min = min(values) + used_max = max(values) + constraints_info += f"\n Currently used: [{used_min:.2f}, {used_max:.2f}]" + + # Check if the parameter space has been fully explored + range_used = (used_max - used_min) / (max_val - min_val) + if range_used < 0.5: + constraints_info += f" (Only {range_used*100:.1f}% of range explored)" + + return constraints_info + + def _check_constraints_compliance(self, data: Dict) -> str: + """Check Constraint Compliance Tool - Implementation""" + violations = [] + constraint_checks = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and run.get('parameters'): + params = run['parameters'] + + # Check the basic scope constraints + for param, value in params.items(): + if param in self.param_constraints: + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + if value < min_val or value > max_val: + violations.append(f"{param}={value} not in [{min_val}, {max_val}]") + + # Check domain constraints + if not self._validate_domain_constraints(params): + violations.append(f"Domain constraints violated for run with params: {params}") + + if violations: + constraint_checks.append(f"Constraint violations found in {len(violations)} cases:") + constraint_checks.extend(violations[:5]) # Only display the first 5 + else: + constraint_checks.append("All parameters comply with constraints") + + # Check the effectiveness of parameter combinations + successful_count = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('success') and run.get('parameters')) + total_with_params = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('parameters')) + + if total_with_params > 0: + success_rate = successful_count / total_with_params * 100 + constraint_checks.append(f"\nParameter success rate: {success_rate:.1f}%") + + return "\n".join(constraint_checks) + + def _suggest_improvements(self, stage: str, data: Dict) -> str: + """Provide improvement suggestions based on stages - implementation""" + suggestions = [] + + if stage == 'inspect': + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + total_runs = data.get('log_data', {}).get('summary', {}).get('total_runs', 0) + + suggestions.append(f"Inspection Suggestions for {successful_runs}/{total_runs} successful runs:") + + if successful_runs < total_runs * 0.3: + suggestions.append("- Focus on identifying why runs are failing") + suggestions.append("- Check for common parameter ranges in failed runs") + else: + suggestions.append("- Analyze correlations between parameters and objectives") + suggestions.append("- Identify optimal parameter ranges from successful runs") + + elif stage == 'model': + suggestions.append("Modeling Suggestions:") + suggestions.append("- Use surrogate models for early prediction of results") + suggestions.append("- Balance exploration (trying new regions) and exploitation (refining good regions)") + + # Suggest modeling methods based on data volume + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + if successful_runs < 10: + suggestions.append("- With limited data, use simpler models and focus on exploration") + else: + suggestions.append("- With sufficient data, use more complex models and balance exploration/exploitation") + + elif stage == 'agglomerate': + suggestions.append("Parameter Generation Suggestions:") + suggestions.append("- Generate diverse parameter sets to explore different regions") + suggestions.append("- Focus on promising parameter ranges identified in previous stages") + suggestions.append("- Ensure all generated parameters satisfy domain constraints") + + # Suggest strategies based on goals + if self.objective == 'ECP': + suggestions.append("- For ECP, prioritize timing-critical parameters like clk_period and cell padding") + elif self.objective == 'DWL': + suggestions.append("- For DWL, focus on placement and routing parameters") + + return "\n".join(suggestions) + + def _extract_XY_from_data(self, data: Dict) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]: + """Extracting X and Y arrays from data - Reusing logic in analyze_stetrics""" + feature_vectors = [] + objective_values = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and 'metrics' in run: + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + # Use real values, if not available, use proxy values + objective_values.append(obj_values['value'] if obj_values['value'] is not None else obj_values['surrogate']) + + if feature_vectors and objective_values: + return np.array(feature_vectors), np.array(objective_values) + else: + return None, None + + def _format_analysis_result(self, title: str, result: Dict) -> str: + """Format the analysis result as a readable string""" + formatted = f"=== {title} ===\n" + + for key, value in result.items(): + if key == "model_recommendations": + formatted += "\n--- Model Recommendations ---\n" + for rec_key, rec_value in value.items(): + formatted += f"{rec_key}: {rec_value}\n" + elif isinstance(value, (int, float)): + formatted += f"{key}: {value:.4f}\n" + elif isinstance(value, list) and len(value) > 0 and isinstance(value[0], (int, float)): + # Format numerical list + formatted += f"{key}: [{', '.join(f'{v:.4f}' for v in value[:5])}{'...' if len(value) > 5 else ''}]\n" + else: + formatted += f"{key}: {value}\n" + + return formatted + + def _configure_inspection_with_existing(self, config: Dict, data: Dict) -> str: + """Use existing function configuration to check parameters""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Using configuration to run structural analysis + result = inspect_data_structure(X, Y, config) + + response = f"Inspection configured with: {config}\n" + response += "Key findings:\n" + + # Extract key findings + if "linearity_score" in result: + response += f"- Linearity: {result['linearity_score']:.3f}\n" + if "is_nonlinear" in result: + response += f"- Nonlinear: {result['is_nonlinear']}\n" + if "needs_local_models" in result: + response += f"- Needs local models: {result['needs_local_models']}\n" + if "cluster_sizes" in result: + response += f"- Cluster sizes: {result['cluster_sizes']}\n" + + return response + else: + return "No data available for inspection configuration" + + except Exception as e: + return f"Error in inspection configuration: {str(e)}" + + def _analyze_correlations_with_existing(self, params: Dict, data: Dict) -> str: + """Analyze correlation using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain relevant information + config = {"correlation_threshold": params.get('threshold', 0.5)} + result = inspect_data_structure(X, Y, config) + + response = "Feature Correlations Analysis:\n" + + if "feature_importance" in result: + response += "Feature importance (correlation with objective):\n" + for i, importance in enumerate(result["feature_importance"]): + response += f"- {self.parameter_names[i]}: {importance:.3f}\n" + + if "has_correlated_features" in result: + response += f"Has highly correlated features: {result['has_correlated_features']}\n" + if "high_correlation_pairs" in result: + response += f"High correlation pairs: {result['high_correlation_pairs']}\n" + + return response + else: + return "No data available for correlation analysis" + + except Exception as e: + return f"Error in correlation analysis: {str(e)}" + + def _cluster_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Cluster analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain clustering information + result = inspect_data_structure(X, Y, config) + + response = "Cluster Analysis:\n" + + if "cluster_sizes" in result: + response += f"Cluster sizes: {result['cluster_sizes']}\n" + if "cluster_balance" in result: + response += f"Cluster balance: {result['cluster_balance']:.3f}\n" + if "cluster_y_means" in result: + response += "Cluster objective means:\n" + for i, mean in enumerate(result["cluster_y_means"]): + response += f"- Cluster {i}: {mean:.4f}\n" + if "needs_local_models" in result: + response += f"Recommend local models: {result['needs_local_models']}\n" + + return response + else: + return "No data available for cluster analysis" + + except Exception as e: + return f"Error in cluster analysis: {str(e)}" + + def _manifold_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Perform manifold analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_manifold_structure(X, config) + return self._format_analysis_result("Manifold Structure Analysis", result) + else: + return "No data available for manifold analysis" + + except Exception as e: + return f"Error in manifold analysis: {str(e)}" + + def _local_structure_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for local structure analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_local_structure(X, config) + return self._format_analysis_result("Local Structure Analysis", result) + else: + return "No data available for local structure analysis" + + except Exception as e: + return f"Error in local structure analysis: {str(e)}" + + def _get_model_recommendations_from_existing(self, data: Dict) -> str: + """Obtain model recommendations from existing analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_structure(X, Y) + + if "model_recommendations" in result: + recommendations = result["model_recommendations"] + response = "Model Recommendations from Data Analysis:\n" + + for key, value in recommendations.items(): + if key == "feature_weights" and isinstance(value, list): + response += f"{key}: [" + response += ", ".join(f"{w:.3f}" for w in value[:5]) + if len(value) > 5: + response += ", ..." + response += "]\n" + else: + response += f"{key}: {value}\n" + + return response + else: + return "No model recommendations available" + else: + return "No data available for model recommendations" + + except Exception as e: + return f"Error getting model recommendations: {str(e)}" + + + def _configure_model_with_existing(self, config: Dict, data: Dict) -> str: + """Configure the model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Create a model using configuration + kernel_type = config.get('kernel_type', 'matern') + preprocessing = config.get('preprocessing', 'standard') + acquisition = config.get('acquisition', 'ei') + + # Create Preprocessor + preprocessor = create_preprocessor(preprocessing) + + # Create acquisition function + acq_function = create_acquisition_function(acquisition) + + response = f"Model configured successfully:\n" + response += f"- Kernel type: {kernel_type}\n" + response += f"- Preprocessing: {preprocessing}\n" + response += f"- Acquisition function: {acquisition}\n" + response += f"- Data shape: {X.shape}\n" + + # If the amount of data is sufficient, a model can be created for testing + if len(X) >= 2: + model = create_model(X, Y, kernel_type=kernel_type) + response += f"- Model created successfully with {len(X)} samples\n" + else: + response += f"- Insufficient data for model creation (need at least 2 samples, have {len(X)})\n" + + return response + else: + return "No data available for model configuration" + + except Exception as e: + return f"Error in model configuration: {str(e)}" + + def _evaluate_surrogate_with_existing(self, params: Dict, data: Dict) -> str: + """Evaluate the proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Extract proxy values (if any) + surrogate_values = None + if 'surrogates' in data.get('metrics', {}): + surrogate_values = np.array(data['metrics']['surrogates']) + + # Use existing functions to process proxy data + if surrogate_values is not None: + X_processed, y_combined, uncertainty = handle_surrogate_data(X, Y, surrogate_values) + + response = "Surrogate Model Evaluation:\n" + response += f"- Original data points: {len(Y)}\n" + response += f"- Valid target values: {np.sum(~np.isnan(Y))}\n" + response += f"- Surrogate values used: {np.sum(np.isnan(Y))}\n" + response += f"- Combined data points: {len(y_combined)}\n" + + if len(uncertainty) > 0: + response += f"- Average surrogate uncertainty: {np.mean(uncertainty):.4f}\n" + + return response + else: + return "No surrogate data available for evaluation" + else: + return "No data available for surrogate evaluation" + + except Exception as e: + return f"Error in surrogate evaluation: {str(e)}" + + def _select_acquisition_with_existing(self, method: str, data: Dict) -> str: + """Use existing functions to select collection functions""" + try: + # Create a collection function using an existing function + acq_function = create_acquisition_function(method) + + response = f"Acquisition function selected: {method.upper()}\n" + + # Provide explanations for different collection functions + explanations = { + 'ei': "Expected Improvement - balances improvement probability and magnitude", + 'ucb': "Upper Confidence Bound - favors exploration of uncertain regions", + 'pi': "Probability of Improvement - focuses on areas likely to improve", + 'augmented_ei': "Augmented EI - combines EI with exploration bonus" + } + + response += f"Explanation: {explanations.get(method, 'No explanation available')}\n" + + # Provide recommendations based on data characteristics + X, Y = self._extract_XY_from_data(data) + if X is not None and Y is not None: + if len(Y) < 10: + response += "Recommendation: With limited data, consider using UCB for better exploration\n" + else: + response += "Recommendation: With sufficient data, EI or Augmented EI are good choices\n" + + return response + + except Exception as e: + return f"Error in acquisition function selection: {str(e)}" + + def _create_surrogate_model_with_existing(self, config: Dict, data: Dict) -> str: + """Create a proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + kernel_type = config.get('kernel_type', 'matern') + noise_level = config.get('noise_level', 1e-6) + + # Create a model using existing functions + model = create_model(X, Y, noise_level=noise_level, kernel_type=kernel_type) + + response = f"Surrogate Model Created:\n" + response += f"- Kernel: {kernel_type}\n" + response += f"- Data points: {len(X)}\n" + response += f"- Features: {X.shape[1]}\n" + response += f"- Kernel parameters: {model.kernel_}\n" + + # Test model prediction + if len(X) > 0: + predictions, stds = predict_with_model(model, X[:1]) # Test a point + response += f"- Test prediction successful\n" + response += f"- Prediction range: [{predictions[0]:.4f} ± {stds[0]:.4f}]\n" + + return response + else: + return "No data available for model creation" + + except Exception as e: + return f"Error in surrogate model creation: {str(e)}" + + def _evaluate_timing_model_with_existing(self, data: Dict) -> str: + """Evaluate timing models using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate timing models using existing functions + results = evaluate_timing_model(context) + + response = "Timing Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in timing model evaluation: {str(e)}" + + def _evaluate_wirelength_model_with_existing(self, data: Dict) -> str: + """Evaluate the wire length model using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate the wire length model using existing functions + results = evaluate_wirelength_model(context) + + response = "Wirelength Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in wirelength model evaluation: {str(e)}" + + def _generate_parameters_with_existing(self, count: int, data: Dict) -> str: + """Generate parameters using existing functions""" + try: + if count <= 0 or count > 50: + return "Error: count must be between 1 and 50" + + # Obtain parameter dimensions + n_dims = len(self.parameter_names) + + # Use existing Latin hypercube sampling + samples = latin_hypercube(count, n_dims) + + response = f"Parameter Generation using Latin Hypercube:\n" + response += f"- Samples generated: {count}\n" + response += f"- Parameter dimensions: {n_dims}\n" + response += f"- Sampling method: Latin Hypercube\n" + + # Display parameter range information + response += "\nParameter Ranges:\n" + for i, param in enumerate(self.parameter_names): + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + response += f"- {param}: [{min_val}, {max_val}] ({constraint['type']})\n" + + return response + + except Exception as e: + return f"Error in parameter generation: {str(e)}" + + def _latin_hypercube_sampling_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for Latin hypercube sampling""" + try: + n_points = config.get('n_points', 10) + n_dims = len(self.parameter_names) + + # Use the existing Latin hypercube sampling function + samples = latin_hypercube(n_points, n_dims) + + response = f"Latin Hypercube Sampling:\n" + response += f"- Points: {n_points}\n" + response += f"- Dimensions: {n_dims}\n" + response += f"- Sample shape: {samples.shape}\n" + + # Display sampling statistics + response += f"- Sample range: [{samples.min():.3f}, {samples.max():.3f}]\n" + response += f"- Sample mean: {samples.mean():.3f}\n" + response += f"- Sample std: {samples.std():.3f}\n" + + return response + + except Exception as e: + return f"Error in Latin hypercube sampling: {str(e)}" + + def _configure_selection_with_existing(self, config: Dict, data: Dict) -> str: + """Configure selection strategy using existing functions""" + try: + method = config.get('method', 'hybrid') + quality_weight = config.get('quality_weight', 0.7) + uncertainty_bonus = config.get('uncertainty_bonus', 0.2) + n_points = config.get('n_points', 10) + + response = f"Selection Strategy Configured:\n" + response += f"- Method: {method}\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Uncertainty bonus: {uncertainty_bonus}\n" + response += f"- Points to select: {n_points}\n" + + # Provide explanations for different methods + method_descriptions = { + "kmeans": "K-means clustering - selects best point from each cluster", + "hybrid": "Hybrid approach - balances quality and diversity", + "entropy": "Entropy-based - maximizes information diversity", + "graph": "Graph-based - uses network centrality measures" + } + + response += f"Method description: {method_descriptions.get(method, 'No description')}\n" + + return response + + except Exception as e: + return f"Error in selection configuration: {str(e)}" + + + def _create_quality_scores_with_existing(self, config: Dict, data: Dict) -> str: + """Create a quality score using an existing function""" + try: + # Extract necessary information from data + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Simulation model predictions and uncertainties (in practical use, these should come from real models) + model_predictions = Y # Using real values as a proxy for prediction + model_uncertainties = np.ones_like(Y) * 0.1 # Simulate uncertainty + + # Create a quality score using an existing function + quality_scores = create_quality_scores(X, Y, model_predictions, model_uncertainties) + + response = "Quality Scores Created:\n" + response += f"- Data points: {len(X)}\n" + response += f"- Quality score range: [{quality_scores.min():.4f}, {quality_scores.max():.4f}]\n" + response += f"- Quality score mean: {quality_scores.mean():.4f}\n" + response += f"- Quality score std: {quality_scores.std():.4f}\n" + + response += f"- First 5 quality scores: {quality_scores[:5].tolist()}\n" + + if 'selection_data' not in data: + data['selection_data'] = {} + data['selection_data']['quality_scores'] = quality_scores + data['selection_data']['X'] = X + data['selection_data']['Y'] = Y + + return response + else: + return "No data available for quality score creation" + + except Exception as e: + return f"Error in quality score creation: {str(e)}" + + def _select_points_with_existing(self, config: Dict, data: Dict) -> str: + """_select_points_with_existing""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + method = config.get('method', 'hybrid') + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + selection_config = { + "quality_weight": quality_weight, + "uncertainty_bonus": config.get('uncertainty_bonus', 0.2) + } + + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points, + config=selection_config + ) + + response = f"Points Selected using {method.upper()} method:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Selected quality scores: {selected_qualities.tolist()}\n" + response += f"- Average quality of selected: {selected_qualities.mean():.4f}\n" + + # store selection data + data['selection_data']['selected_indices'] = selected_indices + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in point selection: {str(e)}" + + def _compare_selection_methods_with_existing(self, config: Dict, data: Dict) -> str: + """compare selection methods with existing(""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 5) + methods = ['kmeans', 'hybrid', 'entropy', 'graph'] + + response = "Selection Method Comparison:\n" + response += f"- Comparing {len(methods)} methods\n" + response += f"- Points to select: {n_points}\n\n" + + for method in methods: + try: + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points + ) + + selected_qualities = quality_scores[selected_indices] + + response += f"**{method.upper()}**:\n" + response += f" - Selected indices: {selected_indices.tolist()}\n" + response += f" - Avg quality: {selected_qualities.mean():.4f}\n" + response += f" - Quality range: [{selected_qualities.min():.4f}, {selected_qualities.max():.4f}]\n" + + except Exception as e: + response += f"**{method.upper()}**: Error - {str(e)}\n" + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in method comparison: {str(e)}" + + def _kmeans_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using K-means selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using K-means selecting function + selected_indices = kmeans_select(X, quality_scores, n_points) + + response = "K-means Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + response += f"- Quality diversity: {selected_qualities.std():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'kmeans' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in K-means selection: {str(e)}" + + def _hybrid_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing hybrid selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + distance_matrix = cdist(X, X) + + # using hybrid_select function + selected_indices = hybrid_select( + X, quality_scores, distance_matrix, + n_points, quality_weight + ) + + response = "Hybrid Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + selected_points = X[selected_indices] + min_distances = np.min(cdist(selected_points, selected_points) + np.eye(len(selected_points)) * 1e6, axis=1) + response += f"- Minimum inter-point distance: {min_distances.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'hybrid' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in hybrid selection: {str(e)}" + + def _entropy_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing entropy selecting methods""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using entropy selecting function + selected_indices = entropy_select(X, quality_scores, n_points) + + response = "Entropy-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'entropy' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in entropy selection: {str(e)}" + + def _graph_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing graph selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using graph selecting function + selected_indices = graph_select(X, quality_scores, n_points) + + response = "Graph-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'graph' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in graph selection: {str(e)}" + + + def _validate_parameters_tool(self, params: Dict) -> str: + validation_results = [] + + for param_name, value in params.items(): + if param_name in self.param_constraints: + constraint = self.param_constraints[param_name] + min_val, max_val = constraint['range'] + param_type = constraint['type'] + + if value < min_val or value > max_val: + validation_results.append(f" {param_name}={value} outside range [{min_val}, {max_val}]") + else: + validation_results.append(f" {param_name}={value} within valid range") + + if self._validate_domain_constraints(params): + validation_results.append("Domain constraints satisfied") + else: + validation_results.append("Domain constraints violated") + + return "Parameter Validation:\n" + "\n".join(validation_results) + + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + tool_instructions = { + 'inspect': ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ), + + 'agglomerate': ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + } + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** + + {stage_contexts.get(stage, '')} + + {tool_instructions.get(stage, '')} + + **Important: Use only tool calls and do not generate text replies!** + """ + + # ========= Splicing RAG ========= + # rag_context = "" + # if self.rag_model is not None and self.rag_embeddings is not None: + # try: + # print("[DEBUG] RAG: Starting retrieval...") + + # # Step 1: Extract error information + # error_summary = "" + # if "log_data" in data: + # all_errors = [] + # for run in data["log_data"].get("runs", []): + # if run.get("errors"): + # all_errors.extend(run["errors"]) + # if all_errors: + # # Retrieve the most recent or frequent errors + # top_errors = all_errors[-3:] # Last 3 posts + # error_summary = "\n".join(top_errors) + # print(f"[DEBUG] Detected {len(all_errors)} error messages. Sample:\n{error_summary}") + + # # Step 2: Construct RAG query + # if error_summary: + # query = ( + # f"Stage: {stage}. Objective: {self.objective}. " + # f"The recent optimization runs failed with errors:\n{error_summary}\n\n" + # "Retrieve relevant OpenROAD documentation, known failure modes, and " + # "potential parameter tuning suggestions that may fix these issues." + # ) + # else: + # query = ( + # f"Stage: {stage}. Objective: {self.objective}. " + # f"Focus on analyzing {stage}-related optimization results. " + # f"Important metrics include wirelength, timing, area, and success rate. " + # f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + # ) + + # # Step 3: Execute search + # rag_context = answerWithRAG( + # query, + # self.rag_embeddings, + # self.rag_model, + # self.rag_docs, + # self.rag_docsDict, + # ) + + # if isinstance(rag_context, dict): # If returning dict + # print(f"[DEBUG] RAG Retrieved {len(rag_context.get('docs', []))} related entries.") + # for doc in rag_context.get("docs", [])[:3]: + # print(f" ↳ {doc['title']} (score={doc['score']:.3f}) from {doc['source']}") + # retrieved_text = rag_context.get("content", "") + # else: + # retrieved_text = rag_context + + # # Step 4: 加入 prompt + # if retrieved_text.strip(): + # prompt += ( + # "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + # f"{retrieved_text}\n" + # "==============================================" + # ) + # print("[DEBUG] RAG: Context successfully added to prompt.") + # else: + # print("[DEBUG] RAG: Empty context retrieved.") + # except Exception as e: + # prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + + if all_errors: + error_summary = "\n".join(all_errors[-5:]) # The last 5 errors + prompt += f""" + + ### Detected Run Errors + {error_summary} + + The model must now act as an **EDA Debugging Assistant**. + Using the retrieved documentation and knowledge, analyze the errors above and: + 1. Identify the root causes of each error (e.g., tool misconfiguration, parameter overflow, timing issues, etc.) + 2. Suggest **specific parameter changes or flow adjustments** to prevent these errors. + 3. Indicate whether the error is likely due to constraints, routing congestion, or timing margin. + 4. Provide a short explanation for each suggestion. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + + """ + print("[DEBUG] Added error-fix section to prompt.") + def _collect_recent_errors(self, data: Dict[str, Any], max_errors=5) -> str: + errors = [] + for run in data.get("log_data", {}).get("runs", []): + if run.get("errors"): + errors.extend(run["errors"]) + print(f"[DEBUG] Found total {len(errors)} errors in all runs.") + return "\n".join(errors[-max_errors:]) if errors else "No errors detected." + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + # """Call Claude to get recommendations for optimization parameters""" + # print(f"\n=== Calling LLM for {stage} stage ===") + """Call LLM to get recommendations for optimization parameters using react framework""" + print(f"\n=== Calling LLM with ReAct framework for {stage} stage ===") + + try: + react_prompt = self._generate_react_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(react_prompt) + print("========================") + available_tools = self._create_react_tools(stage, data) + + react_result = self.react_framework.run_react_cycle( + initial_prompt=react_prompt, + available_tools=available_tools, + max_steps=1, + temperature=0.1 + ) + # === If an error occurs, enter Debug mode === + if "log_data" in data and any(run.get("errors") for run in data["log_data"].get("runs", [])): + print("\n[DEBUG] Detected errors in previous runs. Invoking Debug Assistant mode...") + + # Collect error information + all_errors = [] + for run in data["log_data"]["runs"]: + if run.get("errors"): + all_errors.extend(run["errors"]) + error_text = "\n".join(all_errors[-5:]) # Recent entries + + # Construct a Debug Prompt + debug_prompt = f""" + You are now an **EDA Debugging Expert**. + Based on the following OpenROAD errors and RAG documentation, analyze and provide concrete repair suggestions. + + Errors Detected: + {error_text} + + Please identify: + 1. Root cause of each error. + 2. Specific parameter changes (e.g., in floorplan, CTS, or routing stages) that could fix the issue. + 3. Whether this issue is due to timing, congestion, or setup misconfiguration. + 4. One short explanation per fix. + + Return your answer in **JSON format** like: + {{ + "error_analysis": [ + {{ + "error": "...", + "cause": "...", + "fix": "...", + "params_to_adjust": {{"param_name": "new_value"}} + }} + ] + }} + """ + + # Call LLM to output repair suggestions + debug_result = self.react_framework.run_react_cycle( + initial_prompt=debug_prompt, + available_tools=available_tools, + max_steps=1, + temperature=0.2 + ) + + print("\n[DEBUG] LLM Debug Assistant Result:") + print(debug_result.get("final_answer", "")) + + # Save repair suggestions to the main results + react_result["error_fix_suggestions"] = debug_result.get("final_answer", "") + # Write files for manual viewing + with open("logs/error_fix_suggestions.json", "w") as f: + f.write(debug_result.get("final_answer", "")) + print(f"\n=== ReAct Cycle Completed ===") + print(f"Completed steps: {react_result.get('completed_steps', 0)}/{react_result.get('max_steps', 8)}") + print(f"Final Answer: {react_result['final_answer']}") + + configs = self._parse_react_final_answer(react_result["final_answer"], stage) + + if react_result.get('reasoning_history'): + print(f"\n=== Reasoning History ({len(react_result['reasoning_history'])} steps) ===") + for step in react_result['reasoning_history']: + print(f"Step {step['step']}: {step.get('thought', 'No thought')}") + + print(f"Returning config for stage '{stage}': {configs}") + return configs + + except Exception as e: + print(f"Error in LLM call for stage {stage}: {e}") + default_config = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'agglomerate': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + return default_config.get(stage, {}) + + + def _generate_react_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """generate prompts of ReAct framework""" + + stage_descriptions = { + 'inspect': ( + "You are an expert EDA optimization analyst. Analyze the optimization run data to identify patterns " + "and insights. Use the available tools to examine data distributions, correlations, and successful " + "parameter ranges. Your goal is to understand what makes runs successful and provide recommendations " + "for the modeling stage." + ), + 'model': ( + "You are an expert machine learning engineer for EDA optimization. Based on the inspection results, " + "configure the modeling approach for Bayesian optimization. Consider kernel selection, acquisition " + "functions, and surrogate modeling strategies. Balance exploration and exploitation based on the data." + ), + 'agglomerate': ( + "You are an expert parameter optimization specialist. Generate new parameter combinations for the " + "next optimization iteration. Use insights from previous stages to focus on promising regions while " + "maintaining diversity. Ensure all parameters satisfy the domain constraints." + ) + } + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + constraints_text += f"- {param} ({info['type']}, range: {info['range']})\n" + + react_format_instructions = """ +**ReAct Framework Instructions - MUST FOLLOW THIS FORMAT:** + +1. **Thought**: Analyze the current situation and decide what to do next +2. **Action**: Choose one tool from the available tools +3. **Action Input**: Provide the appropriate input for the chosen tool +4. **Observation**: Wait for the tool's response, then continue reasoning + +**Available Tools**: You have access to various analysis tools. Use them to gather information before making decisions. + +**DO NOT include Final Answer until you have completed all necessary analysis.** +**DO NOT predict or simulate tool observations.** +**You will receive actual Observation from tools before continuing.** + +Only after proper analysis: +**Final Answer Format**: Only when you have completed your analysis, provide: +Final Answer: {your_configuration_here} + +**Example**: +Thought: I need to understand the data patterns first. Let me analyze the success rates. +Action: analyze_data_patterns +Action Input: {} +Observation: [Tool response...] +Thought: Now I need to check parameter correlations... +Action: analyze_correlations +Action Input: {} +Observation: [Tool response...] +Final Answer: {"n_clusters": 5, "correlation_threshold": 0.7} +""" + + prompt = f""" + {stage_descriptions[stage]} + + **Current Stage**: {stage.upper()} + **Objective**: {self.objective} + **Platform**: {self.platform} + **Design**: {self.design} + + **Available Data**: + - Total runs: {data.get('log_data', {}).get('summary', {}).get('total_runs', 0)} + - Successful runs: {data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)} + - Failed runs: {data.get('log_data', {}).get('summary', {}).get('failed_runs', 0)} + + {constraints_text} + {react_format_instructions} + + Begin your analysis: + """ + + rag_context = "" + # ======== extract errors ======== + error_summary = self._collect_recent_errors(data) + if error_summary and "No errors" not in error_summary: + print("[DEBUG] RAG: Detected error summary, adding error analysis prompt...") + prompt += f""" + + ### Detected Run Errors + {error_summary} + + You are now acting as an **EDA Debugging Assistant**. + Analyze the errors above and: + 1. Identify the root causes. + 2. Suggest specific parameter changes. + 3. Indicate whether the error is due to timing, routing, or constraints. + 4. Provide short explanations for each. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + """ + else: + print("[DEBUG] No errors found in logs for this stage.") + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict + ) + print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + if rag_context.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{rag_context}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + return prompt + + def _parse_react_final_answer(self, final_answer: str, stage: str) -> Dict[str, Any]: + """parse react final answer""" + + default_configs = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'selection': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + + configs = {} + + if final_answer and "Reached maximum steps" not in final_answer: + try: + json_match = re.search(r'\{.*\}', final_answer, re.DOTALL) + if json_match: + extracted_config = json.loads(json_match.group()) + configs[stage] = extracted_config + print(f"✓ Extracted configuration from ReAct response: {extracted_config}") + else: + configs[stage] = default_configs.get(stage, {}) + print(f"⚠ Using default configuration for {stage} stage") + except Exception as e: + print(f"Error parsing ReAct final answer: {e}") + configs[stage] = default_configs.get(stage, {}) + else: + configs[stage] = default_configs.get(stage, {}) + print(f"ReAct failed to produce answer, using default for {stage}") + + return configs + + def run_iteration(self, num_runs: int) -> None: + """Run a complete iteration of the optimization workflow using react framework""" + print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + # print("\nGetting LLM recommendations for inspection...") + print("\nGetting LLM recommendations with ReAct framework for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + inspection_config = inspect_configs.get('inspect', {}) + print(f"React inspection config: {inspection_config}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics ...") + metrics = self.analyze_metrics( + log_data, + # n_clusters=inspect_configs['inspection']['n_clusters'], + n_clusters=inspection_config.get('n_clusters', 5), + # correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + correlation_threshold=inspection_config.get('correlation_threshold', 0.5) + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + model_config = model_configs.get('model', {}) + print(f"LLM model config: {model_config}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + # kernel_type=model_configs['model']['kernel_type'], + model_config.get('kernel_type', 'matern'), + # preprocessing=model_configs['model']['preprocessing'], + preprocessing=model_config.get('preprocessing', 'robust'), + # acquisition=model_configs['model']['acquisition'], + acquisition=model_config.get('acquisition', 'ei'), + # surrogate_weight=model_configs['model']['surrogate_weight'] + surrogate_weight=model_config.get('surrogate_weight', 0.8) + ) + + # Get LLM recommendations for parameter selection based on all previous results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + selection_config = selection_configs.get('agglomerate', {}) + print(f"LLM selection config: {selection_config}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + # selection_method=selection_configs['selection']['method'], + # quality_weight=selection_configs['selection']['quality_weight'], + # uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + selection_method=selection_config.get('method', 'hybrid'), + quality_weight=selection_config.get('quality_weight', 0.7), + uncertainty_bonus=selection_config.get('uncertainty_bonus', 0.2) + ) + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) != 5: + print("Usage: optimize.py ") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + + workflow = OptimizationWorkflow(platform, design, objective) + workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps + +if __name__ == "__main__": + main() diff --git a/flow-Agent/extract_log_metrics.py b/flow-Agent/extract_log_metrics.py new file mode 100644 index 0000000..916e6be --- /dev/null +++ b/flow-Agent/extract_log_metrics.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +""" +Extract wirelength and clock period metrics from result_dump logs and write a markdown report. + +Targets: +- 5_1_grt.log: line containing "[INFO GRT-0018] Total wirelength:" +- 1_1_yosys_canonicalize.log: line containing "Setting clock period to" +""" + +from __future__ import annotations + +import argparse +import datetime as _dt +import re +from pathlib import Path +from typing import Iterable, Optional, Tuple + + +WIRELENGTH_RE = re.compile(r"\[INFO GRT-0018\]\s*Total wirelength:\s*([0-9.]+)\s*um", re.IGNORECASE) +CLOCK_RE = re.compile(r"Setting clock period to\s*([0-9.]+)", re.IGNORECASE) + + +def parse_numeric(pattern: re.Pattern[str], path: Path) -> Optional[str]: + try: + with path.open("r", encoding="utf-8", errors="ignore") as fh: + for line in fh: + match = pattern.search(line) + if match: + return match.group(1) + except FileNotFoundError: + return None + return None + + +def discover_results(base_dir: Path) -> Iterable[Tuple[str, str, Path]]: + for result_dir in sorted(base_dir.glob("result_dump_*"), key=_numeric_suffix): + logs_root = result_dir / "logs_dump" + if not logs_root.is_dir(): + continue + for base_dir in sorted(logs_root.glob("base_*"), key=_numeric_suffix): + yield ( + result_dir.name.replace("result_dump_", ""), + base_dir.name.replace("base_", ""), + base_dir, + ) + + +def _numeric_suffix(path: Path) -> int: + stem = path.name.split("_")[-1] + try: + return int(stem) + except ValueError: + return 0 + + +def build_markdown(rows: list[dict[str, str]], source_root: Path) -> str: + timestamp = _dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + lines = [ + "# Log Metrics Summary", + "", + f"- Source root: `{source_root}`", + f"- Generated at: {timestamp}", + "", + "| result_dump | base | clock_period | total_wirelength |", + "| --- | --- | --- | --- |", + ] + for row in rows: + lines.append( + f"| {row['result']} | {row['base']} | {row['clock']} | {row['wirelength']} |" + ) + if not rows: + lines.append("| (none) | (none) | (none) | (none) |") + return "\n".join(lines) + "\n" + + +def main() -> None: + repo_root = Path(__file__).resolve().parent + default_output = repo_root / "output_results" / "asap7" / "log_metrics.md" + + parser = argparse.ArgumentParser( + description="Extract wirelength and clock period metrics from result_dump logs." + ) + parser.add_argument( + "--output", + type=Path, + default=default_output, + help=f"Output markdown file (default: {default_output})", + ) + parser.add_argument( + "--source", + type=Path, + default=repo_root / "backup_dir" / "asap7" / "aes", + help="Root directory containing result_dump_* directories.", + ) + args = parser.parse_args() + + rows: list[dict[str, str]] = [] + for result_id, base_id, base_path in discover_results(args.source): + clock = parse_numeric(CLOCK_RE, base_path / "1_1_yosys_canonicalize.log") + wirelength = parse_numeric(WIRELENGTH_RE, base_path / "5_1_grt.log") + rows.append( + { + "result": result_id, + "base": base_id, + "clock": clock or "N/A", + "wirelength": f"{wirelength} um" if wirelength else "N/A", + } + ) + + output_md = build_markdown(rows, args.source) + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text(output_md, encoding="utf-8") + + +if __name__ == "__main__": + main() diff --git a/flow-Agent/figures/README.md b/flow-Agent/figures/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flow-Agent/figures/README.md @@ -0,0 +1 @@ + diff --git a/flow-Agent/figures/expanding.png b/flow-Agent/figures/expanding.png new file mode 100644 index 0000000..64af2b5 Binary files /dev/null and b/flow-Agent/figures/expanding.png differ diff --git a/flow-Agent/figures/framework.png b/flow-Agent/figures/framework.png new file mode 100644 index 0000000..fc104e5 Binary files /dev/null and b/flow-Agent/figures/framework.png differ diff --git a/flow-Agent/maindriver.sh b/flow-Agent/maindriver.sh index 731f332..7dd65e1 100644 --- a/flow-Agent/maindriver.sh +++ b/flow-Agent/maindriver.sh @@ -1,11 +1,11 @@ #!/bin/bash # Default values -TOTAL_ITERS=6 -PARALLEL_RUNS=50 +TOTAL_ITERS=20 +PARALLEL_RUNS=4 TIMEOUT="45m" -TOTAL_CPUS=110 -TOTAL_RAM=220 +TOTAL_CPUS=8 +TOTAL_RAM=16 ECP_WEIGHT=0.5 WL_WEIGHT=0.5 ECP_WEIGHT_SURROGATE=0.5 @@ -82,6 +82,10 @@ if [[ "$objective" != "ECP" && "$objective" != "DWL" && "$objective" != "COMBO" fi # Validate weights sum to 1 +export PLATFORM=$platform +export DESIGN=$design +export OBJECTIVE=$objective + if [[ "$objective" == "COMBO" ]]; then # Ensure jq is installed if ! command -v jq &> /dev/null; then @@ -191,13 +195,14 @@ create_backup() { local platform=$1 local design=$2 local iteration=$3 - local backup_dir="../result_dump_${iteration}" + local backup_dir="./backup_dir/${platform}/${design}/result_dump_${iteration}" echo "Creating backup for iteration ${iteration}..." mkdir -p "$backup_dir" # Move config and constraint files - mv designs/${platform}/${design}/config_*.mk "$backup_dir"/ 2>/dev/null + # mv designs/${platform}/${design}/config_*.mk "$backup_dir"/ 2>/dev/null + cp designs/${platform}/${design}/config_*.mk "$backup_dir"/ 2>/dev/null mv designs/${platform}/${design}/constraint_*.sdc "$backup_dir"/ 2>/dev/null if [[ "$platform" == "asap7" && "$design" == "jpeg" ]]; then mv designs/${platform}/${design}/jpeg_encoder15_7nm_*.sdc "$backup_dir"/ 2>/dev/null @@ -222,7 +227,10 @@ for i in $(seq 1 $TOTAL_ITERS); do echo "Starting iteration $i of $TOTAL_ITERS" # Run sequential phase + # echo '"$platform" "$design" "$PARALLEL_RUNS" "$i"' + echo "${platform}, ${design}, ${PARALLEL_RUNS}, ${i}" ./run_sequential.sh "$platform" "$design" "$PARALLEL_RUNS" "$i" + echo "./run_sequential.sh \"$platform\" \"$design\" \"$PARALLEL_RUNS\" \"$i\"" # Run parallel phase with timeout timeout "$TIMEOUT" ./run_parallel.sh "$platform" "$design" "$PARALLEL_RUNS" || true @@ -235,9 +243,16 @@ for i in $(seq 1 $TOTAL_ITERS); do # Generate constraints for next iteration (skip for last iteration) if [ "$i" -lt "$TOTAL_ITERS" ]; then + for objective in "$objective"; do + echo "Running optimization for $objective" + python3 stage_optimize.py "$platform" "$design" "$objective" --max-react-steps 3 + python3 stage_override.py "$platform" "$design" "$objective" + cp -r results/ results_${platform}_${design}_${objective}/ + done echo "Running optimization for next iteration..." - python3 optimize.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + python3 optimize.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + echo "python3 optimize.py \"$platform\" \"$design\" \"$PARALLEL_RUNS\" \"$i\"" fi done -echo "All iterations complete" \ No newline at end of file +echo "All iterations complete" diff --git a/flow-Agent/maindriver_stage.sh b/flow-Agent/maindriver_stage.sh new file mode 100644 index 0000000..4f0d10b --- /dev/null +++ b/flow-Agent/maindriver_stage.sh @@ -0,0 +1,399 @@ +#!/bin/bash + +# Default values +TOTAL_ITERS=6 +PARALLEL_RUNS=50 +TIMEOUT="45m" +TOTAL_CPUS=110 +TOTAL_RAM=220 +ECP_WEIGHT=0.5 +WL_WEIGHT=0.5 +ECP_WEIGHT_SURROGATE=0.5 +WL_WEIGHT_SURROGATE=0.5 +RUN_STAGE_OPTIMIZE=0 +RUN_STAGE_OVERRIDE=0 +RUN_OPTIMIZE=0 +STAGE_OPT_STAGES="" +STAGE_OPT_MAX_STEPS=3 +STAGE_OPT_TEMPERATURE=0.1 +STAGE_OPT_DRY_RUN=0 +STAGE_OVERRIDE_STAGES="" +STAGE_OVERRIDE_MAX_STEPS=3 +STAGE_OVERRIDE_TEMPERATURE=0.1 +STAGE_OVERRIDE_DRY_RUN=0 +OVERRIDE_FILES=() +OVERRIDE_PARAMS=() + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -p|--platform) + platform="$2" + shift 2 + ;; + -d|--design) + design="$2" + shift 2 + ;; + -i|--iterations) + TOTAL_ITERS="$2" + shift 2 + ;; + -r|--parallel-runs) + PARALLEL_RUNS="$2" + shift 2 + ;; + -t|--timeout) + TIMEOUT="$2" + shift 2 + ;; + -o|--objective) + objective="$2" + shift 2 + ;; + --run-stage-optimize) + RUN_STAGE_OPTIMIZE=1 + shift + ;; + --stage-opt-stages) + STAGE_OPT_STAGES="$2" + shift 2 + ;; + --stage-opt-max-steps) + STAGE_OPT_MAX_STEPS="$2" + shift 2 + ;; + --stage-opt-temperature) + STAGE_OPT_TEMPERATURE="$2" + shift 2 + ;; + --stage-opt-dry-run) + STAGE_OPT_DRY_RUN=1 + shift + ;; + --run-stage-override) + RUN_STAGE_OVERRIDE=1 + shift + ;; + --run-optimize) + RUN_OPTIMIZE=1 + shift + ;; + --override-stages) + STAGE_OVERRIDE_STAGES="$2" + shift 2 + ;; + --override-file) + OVERRIDE_FILES+=("$2") + shift 2 + ;; + --override-param) + OVERRIDE_PARAMS+=("$2") + shift 2 + ;; + --override-max-steps) + STAGE_OVERRIDE_MAX_STEPS="$2" + shift 2 + ;; + --override-temperature) + STAGE_OVERRIDE_TEMPERATURE="$2" + shift 2 + ;; + --override-dry-run) + STAGE_OVERRIDE_DRY_RUN=1 + shift + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Validate required arguments +if [[ -z "$platform" || -z "$design" ]]; then + echo "Usage: $0 -p -d [-i iterations] [-r parallel_runs] [-t timeout] [-o objective]" + echo " platform: asap7 or sky130hd" + echo " design: aes, ibex, or jpeg" + echo " iterations: total number of iterations (default: 6)" + echo " parallel_runs: number of parallel runs (default: 50)" + echo " timeout: timeout per run (default: 45m)" + echo " objective: ecp, wl, or weighted (default: ecp)" + echo " --run-stage-optimize: invoke stage_optimize.py before optimize_raw" + echo " --stage-opt-stages \"synth place\": optional subset passed to stage_optimize.py" + echo " --run-stage-override: invoke stage_override.py with provided overrides" + echo " --override-file file.json / --override-param stage.param=value: supply overrides" + echo " --run-optimize: invoke optimize.py alongside optimize_raw.py each iteration" + exit 1 +fi + +# Set default objective if not specified +objective=${objective:-"ECP"} + +# Convert objective to uppercase for consistency +objective="${objective^^}" + +# Validate platform +if [[ "$platform" != "asap7" && "$platform" != "sky130hd" ]]; then + echo "Error: platform must be either asap7 or sky130hd" + exit 1 +fi + +# Validate design +if [[ "$design" != "aes" && "$design" != "ibex" && "$design" != "jpeg" ]]; then + echo "Error: design must be one of: aes, ibex, jpeg" + exit 1 +fi + +# Validate objective +if [[ "$objective" != "ECP" && "$objective" != "DWL" && "$objective" != "COMBO" ]]; then + echo "Error: objective must be one of: ECP, DWL, COMBO" + exit 1 +fi + +# Validate weights sum to 1 +export PLATFORM=$platform +export DESIGN=$design +export OBJECTIVE=$objective + +if [[ "$objective" == "COMBO" ]]; then + # Ensure jq is installed + if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed. Please install jq." + exit 1 + fi + + # Read weights from opt_config.json + weights=$(jq -r \ + --arg pdk "$platform" \ + --arg design "$design" \ + --arg goal "$objective" \ + '.configurations[] | select(.platform == $pdk and .design == $design and .goal == $goal)' \ + opt_config.json) + + if [[ -z "$weights" || "$weights" == "null" ]]; then + echo "Error: Could not find weights for platform $platform and design $design in opt_config.json." + exit 1 + fi + + # Extract real metric weights + ECP_WEIGHT=$(echo "$weights" | jq -r '.weights.ecp') + WL_WEIGHT=$(echo "$weights" | jq -r '.weights.dwl') + + # Extract surrogate metric weights + ECP_WEIGHT_SURROGATE=$(echo "$weights" | jq -r '.weights_surrogate.ecp') + WL_WEIGHT_SURROGATE=$(echo "$weights" | jq -r '.weights_surrogate.dwl') + + # Validate that the weights sum to 1 + weight_sum=$(echo "$ECP_WEIGHT + $WL_WEIGHT" | bc -l) + if (( $(echo "$weight_sum != 1" | bc -l) )); then + echo "Error: ECP_WEIGHT ($ECP_WEIGHT) and WL_WEIGHT ($WL_WEIGHT) must sum to 1." + exit 1 + fi + + surrogate_weight_sum=$(echo "$ECP_WEIGHT_SURROGATE + $WL_WEIGHT_SURROGATE" | bc -l) + if (( $(echo "$surrogate_weight_sum != 1" | bc -l) )); then + echo "Error: ECP_WEIGHT_SURROGATE ($ECP_WEIGHT_SURROGATE) and WL_WEIGHT_SURROGATE ($WL_WEIGHT_SURROGATE) must sum to 1." + exit 1 + fi + + # Export weights for use in optimize.py + export ECP_WEIGHT + export WL_WEIGHT + export ECP_WEIGHT_SURROGATE + export WL_WEIGHT_SURROGATE +fi + +# Calculate resources per run +cpus_per_run=$(( TOTAL_CPUS / PARALLEL_RUNS )) +ram_per_run=$(( TOTAL_RAM / PARALLEL_RUNS )) + +# Ensure minimum resources +if [[ $cpus_per_run -lt 2 ]]; then + echo "Warning: Not enough CPUs. Reducing parallel runs to $((TOTAL_CPUS / 2))" + PARALLEL_RUNS=$((TOTAL_CPUS / 2)) + cpus_per_run=2 +fi + +if [[ $ram_per_run -lt 4 ]]; then + echo "Warning: Not enough RAM. Reducing parallel runs to $((TOTAL_RAM / 4))" + PARALLEL_RUNS=$((TOTAL_RAM / 4)) + ram_per_run=4 +fi + +# Export resource variables for child scripts +export PARALLEL_RUNS +export CPUS_PER_RUN=$cpus_per_run +export RAM_PER_RUN=$ram_per_run +export TIMEOUT + +# Create logs directory +mkdir -p logs + +# Define the line numbers for DESIGN_CONFIG lines +start_line=9 +end_line=15 + +# Function to comment all DESIGN_CONFIG lines +comment_all_design_configs() { + sed -i "${start_line},${end_line} s/^\([^#]\)/#\1/" Makefile +} + +# Function to uncomment a specific DESIGN_CONFIG line +uncomment_design_config_line() { + local line_num=$1 + sed -i "${line_num} s/^#//" Makefile +} + +# Comment all DESIGN_CONFIG lines first +comment_all_design_configs + +# Find the line number matching the desired DESIGN_CONFIG +config_pattern="DESIGN_CONFIG=./designs/${platform}/${design}/config_\\\$(INT_PARAM).mk" +line_num=$(grep -n "$config_pattern" Makefile | cut -d: -f1) + +if [ -n "$line_num" ]; then + # Uncomment the specific DESIGN_CONFIG line + uncomment_design_config_line $line_num +else + echo "Error: Could not find DESIGN_CONFIG line for platform: $platform, design: $design" + exit 1 +fi + +# Function to create backup +create_backup() { + local platform=$1 + local design=$2 + local iteration=$3 + local backup_dir="./backup_dir/${platform}/${design}/result_dump_${iteration}" + + echo "Creating backup for iteration ${iteration}..." + mkdir -p "$backup_dir" + + # Move config and constraint files + # mv designs/${platform}/${design}/config_*.mk "$backup_dir"/ 2>/dev/null + cp designs/${platform}/${design}/config_*.mk "$backup_dir"/ 2>/dev/null + mv designs/${platform}/${design}/constraint_*.sdc "$backup_dir"/ 2>/dev/null + if [[ "$platform" == "asap7" && "$design" == "jpeg" ]]; then + mv designs/${platform}/${design}/jpeg_encoder15_7nm_*.sdc "$backup_dir"/ 2>/dev/null + fi + + # Move logs + mkdir -p "$backup_dir/logs_dump" + mv logs/${platform}/${design}/* "$backup_dir/logs_dump"/ 2>/dev/null + + # Move results + mkdir -p "$backup_dir/results_dump" + mv results/${platform}/${design}/* "$backup_dir/results_dump"/ 2>/dev/null + + # Move platform_design log files from current directory + mv ${platform}_${design}*.log "$backup_dir"/ 2>/dev/null + + echo "Backup created in ${backup_dir}" +} + +run_stage_optimize() { + local cmd=(python3 stage_optimize.py "$platform" "$design" "$objective" "--max-react-steps" "$STAGE_OPT_MAX_STEPS" "--temperature" "$STAGE_OPT_TEMPERATURE") + + if [[ -n "$STAGE_OPT_STAGES" ]]; then + read -r -a stage_list <<< "$STAGE_OPT_STAGES" + if [[ ${#stage_list[@]} -gt 0 ]]; then + cmd+=("--stages") + for stage_name in "${stage_list[@]}"; do + cmd+=("$stage_name") + done + fi + fi + + if [[ "$STAGE_OPT_DRY_RUN" -eq 1 ]]; then + cmd+=("--dry-run") + fi + + echo "Running stage_optimize.py: ${cmd[*]}" + "${cmd[@]}" +} + +run_stage_override() { + if [[ ${#OVERRIDE_FILES[@]} -eq 0 && ${#OVERRIDE_PARAMS[@]} -eq 0 ]]; then + echo "Error: --run-stage-override requires at least one --override-file or --override-param." + exit 1 + fi + + local cmd=(python3 stage_override.py "$platform" "$design" "$objective" "--max-react-steps" "$STAGE_OVERRIDE_MAX_STEPS" "--temperature" "$STAGE_OVERRIDE_TEMPERATURE") + + if [[ -n "$STAGE_OVERRIDE_STAGES" ]]; then + read -r -a override_stage_list <<< "$STAGE_OVERRIDE_STAGES" + if [[ ${#override_stage_list[@]} -gt 0 ]]; then + cmd+=("--stages") + for stage_name in "${override_stage_list[@]}"; do + cmd+=("$stage_name") + done + fi + fi + + for override_file in "${OVERRIDE_FILES[@]}"; do + cmd+=("--overrides-file" "$override_file") + done + + for override_param in "${OVERRIDE_PARAMS[@]}"; do + cmd+=("--override" "$override_param") + done + + if [[ "$STAGE_OVERRIDE_DRY_RUN" -eq 1 ]]; then + cmd+=("--dry-run") + fi + + echo "Running stage_override.py: ${cmd[*]}" + "${cmd[@]}" +} + +# Main iteration loop +for i in $(seq 1 $TOTAL_ITERS); do + echo "Starting iteration $i of $TOTAL_ITERS" + + # Run sequential phase + # echo '"$platform" "$design" "$PARALLEL_RUNS" "$i"' + echo "${platform}, ${design}, ${PARALLEL_RUNS}, ${i}" + ./run_sequential.sh "$platform" "$design" "$PARALLEL_RUNS" "$i" + echo "./run_sequential.sh \"$platform\" \"$design\" \"$PARALLEL_RUNS\" \"$i\"" + + # Run parallel phase with timeout + timeout "$TIMEOUT" ./run_parallel.sh "$platform" "$design" "$PARALLEL_RUNS" || true + + # Kill any remaining parallel jobs + pkill -P $$ || true + + # Create backup of this iteration's results + create_backup "$platform" "$design" "$i" + + # Generate constraints for next iteration (skip for last iteration) + if [ "$i" -lt "$TOTAL_ITERS" ]; then + # for objective in "$objective"; do + # echo "Running optimization for $objective" + # python3 stage_optimize.py "$platform" "$design" "$objective" --max-react-steps 3 + # cp -r results/ results_${platform}_${design}_${objective}/ + # done + echo "Running optimization for next iteration..." + + if [[ "$RUN_STAGE_OVERRIDE" -eq 1 ]]; then + echo "Applying explicit stage overrides before next iteration..." + run_stage_override + fi + + if [[ "$RUN_STAGE_OPTIMIZE" -eq 1 ]]; then + echo "Requesting stage-level recommendations..." + run_stage_optimize + fi + + # python3 optimize.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + # python3 optimize_rag.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + # python3 optimize_react.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + # python3 optimize_raw.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + if [[ "$RUN_OPTIMIZE" -eq 1 ]]; then + echo "Running optimize_dual.py for additional refinement..." + python3 optimize_dual.py "$platform" "$design" "$objective" "$PARALLEL_RUNS" + fi + fi +done + +echo "All iterations complete" diff --git a/flow-Agent/models/mxbai-embed-large-v1/1_Pooling/config.json b/flow-Agent/models/mxbai-embed-large-v1/1_Pooling/config.json new file mode 100644 index 0000000..553a16b --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/1_Pooling/config.json @@ -0,0 +1,10 @@ +{ + "word_embedding_dimension": 1024, + "pooling_mode_cls_token": true, + "pooling_mode_mean_tokens": false, + "pooling_mode_max_tokens": false, + "pooling_mode_mean_sqrt_len_tokens": false, + "pooling_mode_weightedmean_tokens": false, + "pooling_mode_lasttoken": false, + "include_prompt": true +} \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/LICENSE b/flow-Agent/models/mxbai-embed-large-v1/LICENSE new file mode 100644 index 0000000..0836af1 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2024 mixedbread ai inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/README.md b/flow-Agent/models/mxbai-embed-large-v1/README.md new file mode 100644 index 0000000..177c76e --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/README.md @@ -0,0 +1,2845 @@ +--- +tags: +- mteb +- transformers.js +- transformers +model-index: +- name: mxbai-angle-large-v1 + results: + - task: + type: Classification + dataset: + type: mteb/amazon_counterfactual + name: MTEB AmazonCounterfactualClassification (en) + config: en + split: test + revision: e8379541af4e31359cca9fbcf4b00f2671dba205 + metrics: + - type: accuracy + value: 75.044776119403 + - type: ap + value: 37.7362433623053 + - type: f1 + value: 68.92736573359774 + - task: + type: Classification + dataset: + type: mteb/amazon_polarity + name: MTEB AmazonPolarityClassification + config: default + split: test + revision: e2d317d38cd51312af73b3d32a06d1a08b442046 + metrics: + - type: accuracy + value: 93.84025000000001 + - type: ap + value: 90.93190875404055 + - type: f1 + value: 93.8297833897293 + - task: + type: Classification + dataset: + type: mteb/amazon_reviews_multi + name: MTEB AmazonReviewsClassification (en) + config: en + split: test + revision: 1399c76144fd37290681b995c656ef9b2e06e26d + metrics: + - type: accuracy + value: 49.184 + - type: f1 + value: 48.74163227751588 + - task: + type: Retrieval + dataset: + type: arguana + name: MTEB ArguAna + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 41.252 + - type: map_at_10 + value: 57.778 + - type: map_at_100 + value: 58.233000000000004 + - type: map_at_1000 + value: 58.23700000000001 + - type: map_at_3 + value: 53.449999999999996 + - type: map_at_5 + value: 56.376000000000005 + - type: mrr_at_1 + value: 41.679 + - type: mrr_at_10 + value: 57.92699999999999 + - type: mrr_at_100 + value: 58.389 + - type: mrr_at_1000 + value: 58.391999999999996 + - type: mrr_at_3 + value: 53.651 + - type: mrr_at_5 + value: 56.521 + - type: ndcg_at_1 + value: 41.252 + - type: ndcg_at_10 + value: 66.018 + - type: ndcg_at_100 + value: 67.774 + - type: ndcg_at_1000 + value: 67.84400000000001 + - type: ndcg_at_3 + value: 57.372 + - type: ndcg_at_5 + value: 62.646 + - type: precision_at_1 + value: 41.252 + - type: precision_at_10 + value: 9.189 + - type: precision_at_100 + value: 0.991 + - type: precision_at_1000 + value: 0.1 + - type: precision_at_3 + value: 22.902 + - type: precision_at_5 + value: 16.302 + - type: recall_at_1 + value: 41.252 + - type: recall_at_10 + value: 91.892 + - type: recall_at_100 + value: 99.14699999999999 + - type: recall_at_1000 + value: 99.644 + - type: recall_at_3 + value: 68.706 + - type: recall_at_5 + value: 81.50800000000001 + - task: + type: Clustering + dataset: + type: mteb/arxiv-clustering-p2p + name: MTEB ArxivClusteringP2P + config: default + split: test + revision: a122ad7f3f0291bf49cc6f4d32aa80929df69d5d + metrics: + - type: v_measure + value: 48.97294504317859 + - task: + type: Clustering + dataset: + type: mteb/arxiv-clustering-s2s + name: MTEB ArxivClusteringS2S + config: default + split: test + revision: f910caf1a6075f7329cdf8c1a6135696f37dbd53 + metrics: + - type: v_measure + value: 42.98071077674629 + - task: + type: Reranking + dataset: + type: mteb/askubuntudupquestions-reranking + name: MTEB AskUbuntuDupQuestions + config: default + split: test + revision: 2000358ca161889fa9c082cb41daa8dcfb161a54 + metrics: + - type: map + value: 65.16477858490782 + - type: mrr + value: 78.23583080508287 + - task: + type: STS + dataset: + type: mteb/biosses-sts + name: MTEB BIOSSES + config: default + split: test + revision: d3fb88f8f02e40887cd149695127462bbcf29b4a + metrics: + - type: cos_sim_pearson + value: 89.6277629421789 + - type: cos_sim_spearman + value: 88.4056288400568 + - type: euclidean_pearson + value: 87.94871847578163 + - type: euclidean_spearman + value: 88.4056288400568 + - type: manhattan_pearson + value: 87.73271254229648 + - type: manhattan_spearman + value: 87.91826833762677 + - task: + type: Classification + dataset: + type: mteb/banking77 + name: MTEB Banking77Classification + config: default + split: test + revision: 0fd18e25b25c072e09e0d92ab615fda904d66300 + metrics: + - type: accuracy + value: 87.81818181818181 + - type: f1 + value: 87.79879337316918 + - task: + type: Clustering + dataset: + type: mteb/biorxiv-clustering-p2p + name: MTEB BiorxivClusteringP2P + config: default + split: test + revision: 65b79d1d13f80053f67aca9498d9402c2d9f1f40 + metrics: + - type: v_measure + value: 39.91773608582761 + - task: + type: Clustering + dataset: + type: mteb/biorxiv-clustering-s2s + name: MTEB BiorxivClusteringS2S + config: default + split: test + revision: 258694dd0231531bc1fd9de6ceb52a0853c6d908 + metrics: + - type: v_measure + value: 36.73059477462478 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackAndroidRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 32.745999999999995 + - type: map_at_10 + value: 43.632 + - type: map_at_100 + value: 45.206 + - type: map_at_1000 + value: 45.341 + - type: map_at_3 + value: 39.956 + - type: map_at_5 + value: 42.031 + - type: mrr_at_1 + value: 39.485 + - type: mrr_at_10 + value: 49.537 + - type: mrr_at_100 + value: 50.249 + - type: mrr_at_1000 + value: 50.294000000000004 + - type: mrr_at_3 + value: 46.757 + - type: mrr_at_5 + value: 48.481 + - type: ndcg_at_1 + value: 39.485 + - type: ndcg_at_10 + value: 50.058 + - type: ndcg_at_100 + value: 55.586 + - type: ndcg_at_1000 + value: 57.511 + - type: ndcg_at_3 + value: 44.786 + - type: ndcg_at_5 + value: 47.339999999999996 + - type: precision_at_1 + value: 39.485 + - type: precision_at_10 + value: 9.557 + - type: precision_at_100 + value: 1.552 + - type: precision_at_1000 + value: 0.202 + - type: precision_at_3 + value: 21.412 + - type: precision_at_5 + value: 15.479000000000001 + - type: recall_at_1 + value: 32.745999999999995 + - type: recall_at_10 + value: 62.056 + - type: recall_at_100 + value: 85.088 + - type: recall_at_1000 + value: 96.952 + - type: recall_at_3 + value: 46.959 + - type: recall_at_5 + value: 54.06999999999999 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackEnglishRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 31.898 + - type: map_at_10 + value: 42.142 + - type: map_at_100 + value: 43.349 + - type: map_at_1000 + value: 43.483 + - type: map_at_3 + value: 39.18 + - type: map_at_5 + value: 40.733000000000004 + - type: mrr_at_1 + value: 39.617999999999995 + - type: mrr_at_10 + value: 47.922 + - type: mrr_at_100 + value: 48.547000000000004 + - type: mrr_at_1000 + value: 48.597 + - type: mrr_at_3 + value: 45.86 + - type: mrr_at_5 + value: 46.949000000000005 + - type: ndcg_at_1 + value: 39.617999999999995 + - type: ndcg_at_10 + value: 47.739 + - type: ndcg_at_100 + value: 51.934999999999995 + - type: ndcg_at_1000 + value: 54.007000000000005 + - type: ndcg_at_3 + value: 43.748 + - type: ndcg_at_5 + value: 45.345 + - type: precision_at_1 + value: 39.617999999999995 + - type: precision_at_10 + value: 8.962 + - type: precision_at_100 + value: 1.436 + - type: precision_at_1000 + value: 0.192 + - type: precision_at_3 + value: 21.083 + - type: precision_at_5 + value: 14.752 + - type: recall_at_1 + value: 31.898 + - type: recall_at_10 + value: 57.587999999999994 + - type: recall_at_100 + value: 75.323 + - type: recall_at_1000 + value: 88.304 + - type: recall_at_3 + value: 45.275 + - type: recall_at_5 + value: 49.99 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackGamingRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 40.458 + - type: map_at_10 + value: 52.942 + - type: map_at_100 + value: 53.974 + - type: map_at_1000 + value: 54.031 + - type: map_at_3 + value: 49.559999999999995 + - type: map_at_5 + value: 51.408 + - type: mrr_at_1 + value: 46.27 + - type: mrr_at_10 + value: 56.31699999999999 + - type: mrr_at_100 + value: 56.95099999999999 + - type: mrr_at_1000 + value: 56.98 + - type: mrr_at_3 + value: 53.835 + - type: mrr_at_5 + value: 55.252 + - type: ndcg_at_1 + value: 46.27 + - type: ndcg_at_10 + value: 58.964000000000006 + - type: ndcg_at_100 + value: 62.875 + - type: ndcg_at_1000 + value: 63.969 + - type: ndcg_at_3 + value: 53.297000000000004 + - type: ndcg_at_5 + value: 55.938 + - type: precision_at_1 + value: 46.27 + - type: precision_at_10 + value: 9.549000000000001 + - type: precision_at_100 + value: 1.2409999999999999 + - type: precision_at_1000 + value: 0.13799999999999998 + - type: precision_at_3 + value: 23.762 + - type: precision_at_5 + value: 16.262999999999998 + - type: recall_at_1 + value: 40.458 + - type: recall_at_10 + value: 73.446 + - type: recall_at_100 + value: 90.12400000000001 + - type: recall_at_1000 + value: 97.795 + - type: recall_at_3 + value: 58.123000000000005 + - type: recall_at_5 + value: 64.68 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackGisRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 27.443 + - type: map_at_10 + value: 36.081 + - type: map_at_100 + value: 37.163000000000004 + - type: map_at_1000 + value: 37.232 + - type: map_at_3 + value: 33.308 + - type: map_at_5 + value: 34.724 + - type: mrr_at_1 + value: 29.492 + - type: mrr_at_10 + value: 38.138 + - type: mrr_at_100 + value: 39.065 + - type: mrr_at_1000 + value: 39.119 + - type: mrr_at_3 + value: 35.593 + - type: mrr_at_5 + value: 36.785000000000004 + - type: ndcg_at_1 + value: 29.492 + - type: ndcg_at_10 + value: 41.134 + - type: ndcg_at_100 + value: 46.300999999999995 + - type: ndcg_at_1000 + value: 48.106 + - type: ndcg_at_3 + value: 35.77 + - type: ndcg_at_5 + value: 38.032 + - type: precision_at_1 + value: 29.492 + - type: precision_at_10 + value: 6.249 + - type: precision_at_100 + value: 0.9299999999999999 + - type: precision_at_1000 + value: 0.11199999999999999 + - type: precision_at_3 + value: 15.065999999999999 + - type: precision_at_5 + value: 10.373000000000001 + - type: recall_at_1 + value: 27.443 + - type: recall_at_10 + value: 54.80199999999999 + - type: recall_at_100 + value: 78.21900000000001 + - type: recall_at_1000 + value: 91.751 + - type: recall_at_3 + value: 40.211000000000006 + - type: recall_at_5 + value: 45.599000000000004 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackMathematicaRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 18.731 + - type: map_at_10 + value: 26.717999999999996 + - type: map_at_100 + value: 27.897 + - type: map_at_1000 + value: 28.029 + - type: map_at_3 + value: 23.91 + - type: map_at_5 + value: 25.455 + - type: mrr_at_1 + value: 23.134 + - type: mrr_at_10 + value: 31.769 + - type: mrr_at_100 + value: 32.634 + - type: mrr_at_1000 + value: 32.707 + - type: mrr_at_3 + value: 28.938999999999997 + - type: mrr_at_5 + value: 30.531000000000002 + - type: ndcg_at_1 + value: 23.134 + - type: ndcg_at_10 + value: 32.249 + - type: ndcg_at_100 + value: 37.678 + - type: ndcg_at_1000 + value: 40.589999999999996 + - type: ndcg_at_3 + value: 26.985999999999997 + - type: ndcg_at_5 + value: 29.457 + - type: precision_at_1 + value: 23.134 + - type: precision_at_10 + value: 5.8709999999999996 + - type: precision_at_100 + value: 0.988 + - type: precision_at_1000 + value: 0.13799999999999998 + - type: precision_at_3 + value: 12.852 + - type: precision_at_5 + value: 9.428 + - type: recall_at_1 + value: 18.731 + - type: recall_at_10 + value: 44.419 + - type: recall_at_100 + value: 67.851 + - type: recall_at_1000 + value: 88.103 + - type: recall_at_3 + value: 29.919 + - type: recall_at_5 + value: 36.230000000000004 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackPhysicsRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 30.324 + - type: map_at_10 + value: 41.265 + - type: map_at_100 + value: 42.559000000000005 + - type: map_at_1000 + value: 42.669000000000004 + - type: map_at_3 + value: 38.138 + - type: map_at_5 + value: 39.881 + - type: mrr_at_1 + value: 36.67 + - type: mrr_at_10 + value: 46.774 + - type: mrr_at_100 + value: 47.554 + - type: mrr_at_1000 + value: 47.593 + - type: mrr_at_3 + value: 44.338 + - type: mrr_at_5 + value: 45.723 + - type: ndcg_at_1 + value: 36.67 + - type: ndcg_at_10 + value: 47.367 + - type: ndcg_at_100 + value: 52.623 + - type: ndcg_at_1000 + value: 54.59 + - type: ndcg_at_3 + value: 42.323 + - type: ndcg_at_5 + value: 44.727 + - type: precision_at_1 + value: 36.67 + - type: precision_at_10 + value: 8.518 + - type: precision_at_100 + value: 1.2890000000000001 + - type: precision_at_1000 + value: 0.163 + - type: precision_at_3 + value: 19.955000000000002 + - type: precision_at_5 + value: 14.11 + - type: recall_at_1 + value: 30.324 + - type: recall_at_10 + value: 59.845000000000006 + - type: recall_at_100 + value: 81.77499999999999 + - type: recall_at_1000 + value: 94.463 + - type: recall_at_3 + value: 46.019 + - type: recall_at_5 + value: 52.163000000000004 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackProgrammersRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 24.229 + - type: map_at_10 + value: 35.004000000000005 + - type: map_at_100 + value: 36.409000000000006 + - type: map_at_1000 + value: 36.521 + - type: map_at_3 + value: 31.793 + - type: map_at_5 + value: 33.432 + - type: mrr_at_1 + value: 30.365 + - type: mrr_at_10 + value: 40.502 + - type: mrr_at_100 + value: 41.372 + - type: mrr_at_1000 + value: 41.435 + - type: mrr_at_3 + value: 37.804 + - type: mrr_at_5 + value: 39.226 + - type: ndcg_at_1 + value: 30.365 + - type: ndcg_at_10 + value: 41.305 + - type: ndcg_at_100 + value: 47.028999999999996 + - type: ndcg_at_1000 + value: 49.375 + - type: ndcg_at_3 + value: 35.85 + - type: ndcg_at_5 + value: 38.12 + - type: precision_at_1 + value: 30.365 + - type: precision_at_10 + value: 7.808 + - type: precision_at_100 + value: 1.228 + - type: precision_at_1000 + value: 0.161 + - type: precision_at_3 + value: 17.352 + - type: precision_at_5 + value: 12.42 + - type: recall_at_1 + value: 24.229 + - type: recall_at_10 + value: 54.673 + - type: recall_at_100 + value: 78.766 + - type: recall_at_1000 + value: 94.625 + - type: recall_at_3 + value: 39.602 + - type: recall_at_5 + value: 45.558 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 26.695 + - type: map_at_10 + value: 36.0895 + - type: map_at_100 + value: 37.309416666666664 + - type: map_at_1000 + value: 37.42558333333334 + - type: map_at_3 + value: 33.19616666666666 + - type: map_at_5 + value: 34.78641666666667 + - type: mrr_at_1 + value: 31.486083333333337 + - type: mrr_at_10 + value: 40.34774999999999 + - type: mrr_at_100 + value: 41.17533333333333 + - type: mrr_at_1000 + value: 41.231583333333326 + - type: mrr_at_3 + value: 37.90075 + - type: mrr_at_5 + value: 39.266999999999996 + - type: ndcg_at_1 + value: 31.486083333333337 + - type: ndcg_at_10 + value: 41.60433333333334 + - type: ndcg_at_100 + value: 46.74525 + - type: ndcg_at_1000 + value: 48.96166666666667 + - type: ndcg_at_3 + value: 36.68825 + - type: ndcg_at_5 + value: 38.966499999999996 + - type: precision_at_1 + value: 31.486083333333337 + - type: precision_at_10 + value: 7.29675 + - type: precision_at_100 + value: 1.1621666666666666 + - type: precision_at_1000 + value: 0.1545 + - type: precision_at_3 + value: 16.8815 + - type: precision_at_5 + value: 11.974583333333333 + - type: recall_at_1 + value: 26.695 + - type: recall_at_10 + value: 53.651916666666665 + - type: recall_at_100 + value: 76.12083333333332 + - type: recall_at_1000 + value: 91.31191666666668 + - type: recall_at_3 + value: 40.03575 + - type: recall_at_5 + value: 45.876666666666665 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackStatsRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 25.668000000000003 + - type: map_at_10 + value: 32.486 + - type: map_at_100 + value: 33.371 + - type: map_at_1000 + value: 33.458 + - type: map_at_3 + value: 30.261 + - type: map_at_5 + value: 31.418000000000003 + - type: mrr_at_1 + value: 28.988000000000003 + - type: mrr_at_10 + value: 35.414 + - type: mrr_at_100 + value: 36.149 + - type: mrr_at_1000 + value: 36.215 + - type: mrr_at_3 + value: 33.333 + - type: mrr_at_5 + value: 34.43 + - type: ndcg_at_1 + value: 28.988000000000003 + - type: ndcg_at_10 + value: 36.732 + - type: ndcg_at_100 + value: 41.331 + - type: ndcg_at_1000 + value: 43.575 + - type: ndcg_at_3 + value: 32.413 + - type: ndcg_at_5 + value: 34.316 + - type: precision_at_1 + value: 28.988000000000003 + - type: precision_at_10 + value: 5.7059999999999995 + - type: precision_at_100 + value: 0.882 + - type: precision_at_1000 + value: 0.11299999999999999 + - type: precision_at_3 + value: 13.65 + - type: precision_at_5 + value: 9.417 + - type: recall_at_1 + value: 25.668000000000003 + - type: recall_at_10 + value: 47.147 + - type: recall_at_100 + value: 68.504 + - type: recall_at_1000 + value: 85.272 + - type: recall_at_3 + value: 35.19 + - type: recall_at_5 + value: 39.925 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackTexRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 17.256 + - type: map_at_10 + value: 24.58 + - type: map_at_100 + value: 25.773000000000003 + - type: map_at_1000 + value: 25.899 + - type: map_at_3 + value: 22.236 + - type: map_at_5 + value: 23.507 + - type: mrr_at_1 + value: 20.957 + - type: mrr_at_10 + value: 28.416000000000004 + - type: mrr_at_100 + value: 29.447000000000003 + - type: mrr_at_1000 + value: 29.524 + - type: mrr_at_3 + value: 26.245 + - type: mrr_at_5 + value: 27.451999999999998 + - type: ndcg_at_1 + value: 20.957 + - type: ndcg_at_10 + value: 29.285 + - type: ndcg_at_100 + value: 35.003 + - type: ndcg_at_1000 + value: 37.881 + - type: ndcg_at_3 + value: 25.063000000000002 + - type: ndcg_at_5 + value: 26.983 + - type: precision_at_1 + value: 20.957 + - type: precision_at_10 + value: 5.344 + - type: precision_at_100 + value: 0.958 + - type: precision_at_1000 + value: 0.13799999999999998 + - type: precision_at_3 + value: 11.918 + - type: precision_at_5 + value: 8.596 + - type: recall_at_1 + value: 17.256 + - type: recall_at_10 + value: 39.644 + - type: recall_at_100 + value: 65.279 + - type: recall_at_1000 + value: 85.693 + - type: recall_at_3 + value: 27.825 + - type: recall_at_5 + value: 32.792 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackUnixRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 26.700000000000003 + - type: map_at_10 + value: 36.205999999999996 + - type: map_at_100 + value: 37.316 + - type: map_at_1000 + value: 37.425000000000004 + - type: map_at_3 + value: 33.166000000000004 + - type: map_at_5 + value: 35.032999999999994 + - type: mrr_at_1 + value: 31.436999999999998 + - type: mrr_at_10 + value: 40.61 + - type: mrr_at_100 + value: 41.415 + - type: mrr_at_1000 + value: 41.48 + - type: mrr_at_3 + value: 37.966 + - type: mrr_at_5 + value: 39.599000000000004 + - type: ndcg_at_1 + value: 31.436999999999998 + - type: ndcg_at_10 + value: 41.771 + - type: ndcg_at_100 + value: 46.784 + - type: ndcg_at_1000 + value: 49.183 + - type: ndcg_at_3 + value: 36.437000000000005 + - type: ndcg_at_5 + value: 39.291 + - type: precision_at_1 + value: 31.436999999999998 + - type: precision_at_10 + value: 6.987 + - type: precision_at_100 + value: 1.072 + - type: precision_at_1000 + value: 0.13899999999999998 + - type: precision_at_3 + value: 16.448999999999998 + - type: precision_at_5 + value: 11.866 + - type: recall_at_1 + value: 26.700000000000003 + - type: recall_at_10 + value: 54.301 + - type: recall_at_100 + value: 75.871 + - type: recall_at_1000 + value: 92.529 + - type: recall_at_3 + value: 40.201 + - type: recall_at_5 + value: 47.208 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackWebmastersRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 24.296 + - type: map_at_10 + value: 33.116 + - type: map_at_100 + value: 34.81 + - type: map_at_1000 + value: 35.032000000000004 + - type: map_at_3 + value: 30.105999999999998 + - type: map_at_5 + value: 31.839000000000002 + - type: mrr_at_1 + value: 29.051 + - type: mrr_at_10 + value: 37.803 + - type: mrr_at_100 + value: 38.856 + - type: mrr_at_1000 + value: 38.903999999999996 + - type: mrr_at_3 + value: 35.211 + - type: mrr_at_5 + value: 36.545 + - type: ndcg_at_1 + value: 29.051 + - type: ndcg_at_10 + value: 39.007 + - type: ndcg_at_100 + value: 45.321 + - type: ndcg_at_1000 + value: 47.665 + - type: ndcg_at_3 + value: 34.1 + - type: ndcg_at_5 + value: 36.437000000000005 + - type: precision_at_1 + value: 29.051 + - type: precision_at_10 + value: 7.668 + - type: precision_at_100 + value: 1.542 + - type: precision_at_1000 + value: 0.24 + - type: precision_at_3 + value: 16.14 + - type: precision_at_5 + value: 11.897 + - type: recall_at_1 + value: 24.296 + - type: recall_at_10 + value: 49.85 + - type: recall_at_100 + value: 78.457 + - type: recall_at_1000 + value: 92.618 + - type: recall_at_3 + value: 36.138999999999996 + - type: recall_at_5 + value: 42.223 + - task: + type: Retrieval + dataset: + type: BeIR/cqadupstack + name: MTEB CQADupstackWordpressRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 20.591 + - type: map_at_10 + value: 28.902 + - type: map_at_100 + value: 29.886000000000003 + - type: map_at_1000 + value: 29.987000000000002 + - type: map_at_3 + value: 26.740000000000002 + - type: map_at_5 + value: 27.976 + - type: mrr_at_1 + value: 22.366 + - type: mrr_at_10 + value: 30.971 + - type: mrr_at_100 + value: 31.865 + - type: mrr_at_1000 + value: 31.930999999999997 + - type: mrr_at_3 + value: 28.927999999999997 + - type: mrr_at_5 + value: 30.231 + - type: ndcg_at_1 + value: 22.366 + - type: ndcg_at_10 + value: 33.641 + - type: ndcg_at_100 + value: 38.477 + - type: ndcg_at_1000 + value: 41.088 + - type: ndcg_at_3 + value: 29.486 + - type: ndcg_at_5 + value: 31.612000000000002 + - type: precision_at_1 + value: 22.366 + - type: precision_at_10 + value: 5.3420000000000005 + - type: precision_at_100 + value: 0.828 + - type: precision_at_1000 + value: 0.11800000000000001 + - type: precision_at_3 + value: 12.939 + - type: precision_at_5 + value: 9.094 + - type: recall_at_1 + value: 20.591 + - type: recall_at_10 + value: 46.052 + - type: recall_at_100 + value: 68.193 + - type: recall_at_1000 + value: 87.638 + - type: recall_at_3 + value: 34.966 + - type: recall_at_5 + value: 40.082 + - task: + type: Retrieval + dataset: + type: climate-fever + name: MTEB ClimateFEVER + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 15.091 + - type: map_at_10 + value: 26.38 + - type: map_at_100 + value: 28.421999999999997 + - type: map_at_1000 + value: 28.621999999999996 + - type: map_at_3 + value: 21.597 + - type: map_at_5 + value: 24.12 + - type: mrr_at_1 + value: 34.266999999999996 + - type: mrr_at_10 + value: 46.864 + - type: mrr_at_100 + value: 47.617 + - type: mrr_at_1000 + value: 47.644 + - type: mrr_at_3 + value: 43.312 + - type: mrr_at_5 + value: 45.501000000000005 + - type: ndcg_at_1 + value: 34.266999999999996 + - type: ndcg_at_10 + value: 36.095 + - type: ndcg_at_100 + value: 43.447 + - type: ndcg_at_1000 + value: 46.661 + - type: ndcg_at_3 + value: 29.337999999999997 + - type: ndcg_at_5 + value: 31.824 + - type: precision_at_1 + value: 34.266999999999996 + - type: precision_at_10 + value: 11.472 + - type: precision_at_100 + value: 1.944 + - type: precision_at_1000 + value: 0.255 + - type: precision_at_3 + value: 21.933 + - type: precision_at_5 + value: 17.224999999999998 + - type: recall_at_1 + value: 15.091 + - type: recall_at_10 + value: 43.022 + - type: recall_at_100 + value: 68.075 + - type: recall_at_1000 + value: 85.76 + - type: recall_at_3 + value: 26.564 + - type: recall_at_5 + value: 33.594 + - task: + type: Retrieval + dataset: + type: dbpedia-entity + name: MTEB DBPedia + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 9.252 + - type: map_at_10 + value: 20.923 + - type: map_at_100 + value: 30.741000000000003 + - type: map_at_1000 + value: 32.542 + - type: map_at_3 + value: 14.442 + - type: map_at_5 + value: 17.399 + - type: mrr_at_1 + value: 70.25 + - type: mrr_at_10 + value: 78.17 + - type: mrr_at_100 + value: 78.444 + - type: mrr_at_1000 + value: 78.45100000000001 + - type: mrr_at_3 + value: 76.958 + - type: mrr_at_5 + value: 77.571 + - type: ndcg_at_1 + value: 58.375 + - type: ndcg_at_10 + value: 44.509 + - type: ndcg_at_100 + value: 49.897999999999996 + - type: ndcg_at_1000 + value: 57.269999999999996 + - type: ndcg_at_3 + value: 48.64 + - type: ndcg_at_5 + value: 46.697 + - type: precision_at_1 + value: 70.25 + - type: precision_at_10 + value: 36.05 + - type: precision_at_100 + value: 11.848 + - type: precision_at_1000 + value: 2.213 + - type: precision_at_3 + value: 52.917 + - type: precision_at_5 + value: 45.7 + - type: recall_at_1 + value: 9.252 + - type: recall_at_10 + value: 27.006999999999998 + - type: recall_at_100 + value: 57.008 + - type: recall_at_1000 + value: 80.697 + - type: recall_at_3 + value: 15.798000000000002 + - type: recall_at_5 + value: 20.4 + - task: + type: Classification + dataset: + type: mteb/emotion + name: MTEB EmotionClassification + config: default + split: test + revision: 4f58c6b202a23cf9a4da393831edf4f9183cad37 + metrics: + - type: accuracy + value: 50.88 + - type: f1 + value: 45.545495028653384 + - task: + type: Retrieval + dataset: + type: fever + name: MTEB FEVER + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 75.424 + - type: map_at_10 + value: 83.435 + - type: map_at_100 + value: 83.66900000000001 + - type: map_at_1000 + value: 83.685 + - type: map_at_3 + value: 82.39800000000001 + - type: map_at_5 + value: 83.07 + - type: mrr_at_1 + value: 81.113 + - type: mrr_at_10 + value: 87.77199999999999 + - type: mrr_at_100 + value: 87.862 + - type: mrr_at_1000 + value: 87.86500000000001 + - type: mrr_at_3 + value: 87.17099999999999 + - type: mrr_at_5 + value: 87.616 + - type: ndcg_at_1 + value: 81.113 + - type: ndcg_at_10 + value: 86.909 + - type: ndcg_at_100 + value: 87.746 + - type: ndcg_at_1000 + value: 88.017 + - type: ndcg_at_3 + value: 85.368 + - type: ndcg_at_5 + value: 86.28099999999999 + - type: precision_at_1 + value: 81.113 + - type: precision_at_10 + value: 10.363 + - type: precision_at_100 + value: 1.102 + - type: precision_at_1000 + value: 0.11399999999999999 + - type: precision_at_3 + value: 32.507999999999996 + - type: precision_at_5 + value: 20.138 + - type: recall_at_1 + value: 75.424 + - type: recall_at_10 + value: 93.258 + - type: recall_at_100 + value: 96.545 + - type: recall_at_1000 + value: 98.284 + - type: recall_at_3 + value: 89.083 + - type: recall_at_5 + value: 91.445 + - task: + type: Retrieval + dataset: + type: fiqa + name: MTEB FiQA2018 + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 22.532 + - type: map_at_10 + value: 37.141999999999996 + - type: map_at_100 + value: 39.162 + - type: map_at_1000 + value: 39.322 + - type: map_at_3 + value: 32.885 + - type: map_at_5 + value: 35.093999999999994 + - type: mrr_at_1 + value: 44.29 + - type: mrr_at_10 + value: 53.516 + - type: mrr_at_100 + value: 54.24 + - type: mrr_at_1000 + value: 54.273 + - type: mrr_at_3 + value: 51.286 + - type: mrr_at_5 + value: 52.413 + - type: ndcg_at_1 + value: 44.29 + - type: ndcg_at_10 + value: 45.268 + - type: ndcg_at_100 + value: 52.125 + - type: ndcg_at_1000 + value: 54.778000000000006 + - type: ndcg_at_3 + value: 41.829 + - type: ndcg_at_5 + value: 42.525 + - type: precision_at_1 + value: 44.29 + - type: precision_at_10 + value: 12.5 + - type: precision_at_100 + value: 1.9720000000000002 + - type: precision_at_1000 + value: 0.245 + - type: precision_at_3 + value: 28.035 + - type: precision_at_5 + value: 20.093 + - type: recall_at_1 + value: 22.532 + - type: recall_at_10 + value: 52.419000000000004 + - type: recall_at_100 + value: 77.43299999999999 + - type: recall_at_1000 + value: 93.379 + - type: recall_at_3 + value: 38.629000000000005 + - type: recall_at_5 + value: 43.858000000000004 + - task: + type: Retrieval + dataset: + type: hotpotqa + name: MTEB HotpotQA + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 39.359 + - type: map_at_10 + value: 63.966 + - type: map_at_100 + value: 64.87 + - type: map_at_1000 + value: 64.92599999999999 + - type: map_at_3 + value: 60.409 + - type: map_at_5 + value: 62.627 + - type: mrr_at_1 + value: 78.717 + - type: mrr_at_10 + value: 84.468 + - type: mrr_at_100 + value: 84.655 + - type: mrr_at_1000 + value: 84.661 + - type: mrr_at_3 + value: 83.554 + - type: mrr_at_5 + value: 84.133 + - type: ndcg_at_1 + value: 78.717 + - type: ndcg_at_10 + value: 72.03399999999999 + - type: ndcg_at_100 + value: 75.158 + - type: ndcg_at_1000 + value: 76.197 + - type: ndcg_at_3 + value: 67.049 + - type: ndcg_at_5 + value: 69.808 + - type: precision_at_1 + value: 78.717 + - type: precision_at_10 + value: 15.201 + - type: precision_at_100 + value: 1.764 + - type: precision_at_1000 + value: 0.19 + - type: precision_at_3 + value: 43.313 + - type: precision_at_5 + value: 28.165000000000003 + - type: recall_at_1 + value: 39.359 + - type: recall_at_10 + value: 76.003 + - type: recall_at_100 + value: 88.197 + - type: recall_at_1000 + value: 95.003 + - type: recall_at_3 + value: 64.97 + - type: recall_at_5 + value: 70.41199999999999 + - task: + type: Classification + dataset: + type: mteb/imdb + name: MTEB ImdbClassification + config: default + split: test + revision: 3d86128a09e091d6018b6d26cad27f2739fc2db7 + metrics: + - type: accuracy + value: 92.83200000000001 + - type: ap + value: 89.33560571859861 + - type: f1 + value: 92.82322915005167 + - task: + type: Retrieval + dataset: + type: msmarco + name: MTEB MSMARCO + config: default + split: dev + revision: None + metrics: + - type: map_at_1 + value: 21.983 + - type: map_at_10 + value: 34.259 + - type: map_at_100 + value: 35.432 + - type: map_at_1000 + value: 35.482 + - type: map_at_3 + value: 30.275999999999996 + - type: map_at_5 + value: 32.566 + - type: mrr_at_1 + value: 22.579 + - type: mrr_at_10 + value: 34.882999999999996 + - type: mrr_at_100 + value: 35.984 + - type: mrr_at_1000 + value: 36.028 + - type: mrr_at_3 + value: 30.964999999999996 + - type: mrr_at_5 + value: 33.245000000000005 + - type: ndcg_at_1 + value: 22.564 + - type: ndcg_at_10 + value: 41.258 + - type: ndcg_at_100 + value: 46.824 + - type: ndcg_at_1000 + value: 48.037 + - type: ndcg_at_3 + value: 33.17 + - type: ndcg_at_5 + value: 37.263000000000005 + - type: precision_at_1 + value: 22.564 + - type: precision_at_10 + value: 6.572 + - type: precision_at_100 + value: 0.935 + - type: precision_at_1000 + value: 0.104 + - type: precision_at_3 + value: 14.130999999999998 + - type: precision_at_5 + value: 10.544 + - type: recall_at_1 + value: 21.983 + - type: recall_at_10 + value: 62.775000000000006 + - type: recall_at_100 + value: 88.389 + - type: recall_at_1000 + value: 97.603 + - type: recall_at_3 + value: 40.878 + - type: recall_at_5 + value: 50.690000000000005 + - task: + type: Classification + dataset: + type: mteb/mtop_domain + name: MTEB MTOPDomainClassification (en) + config: en + split: test + revision: d80d48c1eb48d3562165c59d59d0034df9fff0bf + metrics: + - type: accuracy + value: 93.95120839033288 + - type: f1 + value: 93.73824125055208 + - task: + type: Classification + dataset: + type: mteb/mtop_intent + name: MTEB MTOPIntentClassification (en) + config: en + split: test + revision: ae001d0e6b1228650b7bd1c2c65fb50ad11a8aba + metrics: + - type: accuracy + value: 76.78978568171455 + - type: f1 + value: 57.50180552858304 + - task: + type: Classification + dataset: + type: mteb/amazon_massive_intent + name: MTEB MassiveIntentClassification (en) + config: en + split: test + revision: 31efe3c427b0bae9c22cbb560b8f15491cc6bed7 + metrics: + - type: accuracy + value: 76.24411566913248 + - type: f1 + value: 74.37851403532832 + - task: + type: Classification + dataset: + type: mteb/amazon_massive_scenario + name: MTEB MassiveScenarioClassification (en) + config: en + split: test + revision: 7d571f92784cd94a019292a1f45445077d0ef634 + metrics: + - type: accuracy + value: 79.94620040349699 + - type: f1 + value: 80.21293397970435 + - task: + type: Clustering + dataset: + type: mteb/medrxiv-clustering-p2p + name: MTEB MedrxivClusteringP2P + config: default + split: test + revision: e7a26af6f3ae46b30dde8737f02c07b1505bcc73 + metrics: + - type: v_measure + value: 33.44403096245675 + - task: + type: Clustering + dataset: + type: mteb/medrxiv-clustering-s2s + name: MTEB MedrxivClusteringS2S + config: default + split: test + revision: 35191c8c0dca72d8ff3efcd72aa802307d469663 + metrics: + - type: v_measure + value: 31.659594631336812 + - task: + type: Reranking + dataset: + type: mteb/mind_small + name: MTEB MindSmallReranking + config: default + split: test + revision: 3bdac13927fdc888b903db93b2ffdbd90b295a69 + metrics: + - type: map + value: 32.53833075108798 + - type: mrr + value: 33.78840823218308 + - task: + type: Retrieval + dataset: + type: nfcorpus + name: MTEB NFCorpus + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 7.185999999999999 + - type: map_at_10 + value: 15.193999999999999 + - type: map_at_100 + value: 19.538 + - type: map_at_1000 + value: 21.178 + - type: map_at_3 + value: 11.208 + - type: map_at_5 + value: 12.745999999999999 + - type: mrr_at_1 + value: 48.916 + - type: mrr_at_10 + value: 58.141 + - type: mrr_at_100 + value: 58.656 + - type: mrr_at_1000 + value: 58.684999999999995 + - type: mrr_at_3 + value: 55.521 + - type: mrr_at_5 + value: 57.239 + - type: ndcg_at_1 + value: 47.059 + - type: ndcg_at_10 + value: 38.644 + - type: ndcg_at_100 + value: 36.272999999999996 + - type: ndcg_at_1000 + value: 44.996 + - type: ndcg_at_3 + value: 43.293 + - type: ndcg_at_5 + value: 40.819 + - type: precision_at_1 + value: 48.916 + - type: precision_at_10 + value: 28.607 + - type: precision_at_100 + value: 9.195 + - type: precision_at_1000 + value: 2.225 + - type: precision_at_3 + value: 40.454 + - type: precision_at_5 + value: 34.985 + - type: recall_at_1 + value: 7.185999999999999 + - type: recall_at_10 + value: 19.654 + - type: recall_at_100 + value: 37.224000000000004 + - type: recall_at_1000 + value: 68.663 + - type: recall_at_3 + value: 12.158 + - type: recall_at_5 + value: 14.674999999999999 + - task: + type: Retrieval + dataset: + type: nq + name: MTEB NQ + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 31.552000000000003 + - type: map_at_10 + value: 47.75 + - type: map_at_100 + value: 48.728 + - type: map_at_1000 + value: 48.754 + - type: map_at_3 + value: 43.156 + - type: map_at_5 + value: 45.883 + - type: mrr_at_1 + value: 35.66 + - type: mrr_at_10 + value: 50.269 + - type: mrr_at_100 + value: 50.974 + - type: mrr_at_1000 + value: 50.991 + - type: mrr_at_3 + value: 46.519 + - type: mrr_at_5 + value: 48.764 + - type: ndcg_at_1 + value: 35.632000000000005 + - type: ndcg_at_10 + value: 55.786 + - type: ndcg_at_100 + value: 59.748999999999995 + - type: ndcg_at_1000 + value: 60.339 + - type: ndcg_at_3 + value: 47.292 + - type: ndcg_at_5 + value: 51.766999999999996 + - type: precision_at_1 + value: 35.632000000000005 + - type: precision_at_10 + value: 9.267 + - type: precision_at_100 + value: 1.149 + - type: precision_at_1000 + value: 0.12 + - type: precision_at_3 + value: 21.601 + - type: precision_at_5 + value: 15.539 + - type: recall_at_1 + value: 31.552000000000003 + - type: recall_at_10 + value: 77.62400000000001 + - type: recall_at_100 + value: 94.527 + - type: recall_at_1000 + value: 98.919 + - type: recall_at_3 + value: 55.898 + - type: recall_at_5 + value: 66.121 + - task: + type: Retrieval + dataset: + type: quora + name: MTEB QuoraRetrieval + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 71.414 + - type: map_at_10 + value: 85.37400000000001 + - type: map_at_100 + value: 86.01100000000001 + - type: map_at_1000 + value: 86.027 + - type: map_at_3 + value: 82.562 + - type: map_at_5 + value: 84.284 + - type: mrr_at_1 + value: 82.24000000000001 + - type: mrr_at_10 + value: 88.225 + - type: mrr_at_100 + value: 88.324 + - type: mrr_at_1000 + value: 88.325 + - type: mrr_at_3 + value: 87.348 + - type: mrr_at_5 + value: 87.938 + - type: ndcg_at_1 + value: 82.24000000000001 + - type: ndcg_at_10 + value: 88.97699999999999 + - type: ndcg_at_100 + value: 90.16 + - type: ndcg_at_1000 + value: 90.236 + - type: ndcg_at_3 + value: 86.371 + - type: ndcg_at_5 + value: 87.746 + - type: precision_at_1 + value: 82.24000000000001 + - type: precision_at_10 + value: 13.481000000000002 + - type: precision_at_100 + value: 1.534 + - type: precision_at_1000 + value: 0.157 + - type: precision_at_3 + value: 37.86 + - type: precision_at_5 + value: 24.738 + - type: recall_at_1 + value: 71.414 + - type: recall_at_10 + value: 95.735 + - type: recall_at_100 + value: 99.696 + - type: recall_at_1000 + value: 99.979 + - type: recall_at_3 + value: 88.105 + - type: recall_at_5 + value: 92.17999999999999 + - task: + type: Clustering + dataset: + type: mteb/reddit-clustering + name: MTEB RedditClustering + config: default + split: test + revision: 24640382cdbf8abc73003fb0fa6d111a705499eb + metrics: + - type: v_measure + value: 60.22146692057259 + - task: + type: Clustering + dataset: + type: mteb/reddit-clustering-p2p + name: MTEB RedditClusteringP2P + config: default + split: test + revision: 282350215ef01743dc01b456c7f5241fa8937f16 + metrics: + - type: v_measure + value: 65.29273320614578 + - task: + type: Retrieval + dataset: + type: scidocs + name: MTEB SCIDOCS + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 5.023 + - type: map_at_10 + value: 14.161000000000001 + - type: map_at_100 + value: 16.68 + - type: map_at_1000 + value: 17.072000000000003 + - type: map_at_3 + value: 9.763 + - type: map_at_5 + value: 11.977 + - type: mrr_at_1 + value: 24.8 + - type: mrr_at_10 + value: 37.602999999999994 + - type: mrr_at_100 + value: 38.618 + - type: mrr_at_1000 + value: 38.659 + - type: mrr_at_3 + value: 34.117 + - type: mrr_at_5 + value: 36.082 + - type: ndcg_at_1 + value: 24.8 + - type: ndcg_at_10 + value: 23.316 + - type: ndcg_at_100 + value: 32.613 + - type: ndcg_at_1000 + value: 38.609 + - type: ndcg_at_3 + value: 21.697 + - type: ndcg_at_5 + value: 19.241 + - type: precision_at_1 + value: 24.8 + - type: precision_at_10 + value: 12.36 + - type: precision_at_100 + value: 2.593 + - type: precision_at_1000 + value: 0.402 + - type: precision_at_3 + value: 20.767 + - type: precision_at_5 + value: 17.34 + - type: recall_at_1 + value: 5.023 + - type: recall_at_10 + value: 25.069999999999997 + - type: recall_at_100 + value: 52.563 + - type: recall_at_1000 + value: 81.525 + - type: recall_at_3 + value: 12.613 + - type: recall_at_5 + value: 17.583 + - task: + type: STS + dataset: + type: mteb/sickr-sts + name: MTEB SICK-R + config: default + split: test + revision: a6ea5a8cab320b040a23452cc28066d9beae2cee + metrics: + - type: cos_sim_pearson + value: 87.71506247604255 + - type: cos_sim_spearman + value: 82.91813463738802 + - type: euclidean_pearson + value: 85.5154616194479 + - type: euclidean_spearman + value: 82.91815254466314 + - type: manhattan_pearson + value: 85.5280917850374 + - type: manhattan_spearman + value: 82.92276537286398 + - task: + type: STS + dataset: + type: mteb/sts12-sts + name: MTEB STS12 + config: default + split: test + revision: a0d554a64d88156834ff5ae9920b964011b16384 + metrics: + - type: cos_sim_pearson + value: 87.43772054228462 + - type: cos_sim_spearman + value: 78.75750601716682 + - type: euclidean_pearson + value: 85.76074482955764 + - type: euclidean_spearman + value: 78.75651057223058 + - type: manhattan_pearson + value: 85.73390291701668 + - type: manhattan_spearman + value: 78.72699385957797 + - task: + type: STS + dataset: + type: mteb/sts13-sts + name: MTEB STS13 + config: default + split: test + revision: 7e90230a92c190f1bf69ae9002b8cea547a64cca + metrics: + - type: cos_sim_pearson + value: 89.58144067172472 + - type: cos_sim_spearman + value: 90.3524512966946 + - type: euclidean_pearson + value: 89.71365391594237 + - type: euclidean_spearman + value: 90.35239632843408 + - type: manhattan_pearson + value: 89.66905421746478 + - type: manhattan_spearman + value: 90.31508211683513 + - task: + type: STS + dataset: + type: mteb/sts14-sts + name: MTEB STS14 + config: default + split: test + revision: 6031580fec1f6af667f0bd2da0a551cf4f0b2375 + metrics: + - type: cos_sim_pearson + value: 87.77692637102102 + - type: cos_sim_spearman + value: 85.45710562643485 + - type: euclidean_pearson + value: 87.42456979928723 + - type: euclidean_spearman + value: 85.45709386240908 + - type: manhattan_pearson + value: 87.40754529526272 + - type: manhattan_spearman + value: 85.44834854173303 + - task: + type: STS + dataset: + type: mteb/sts15-sts + name: MTEB STS15 + config: default + split: test + revision: ae752c7c21bf194d8b67fd573edf7ae58183cbe3 + metrics: + - type: cos_sim_pearson + value: 88.28491331695997 + - type: cos_sim_spearman + value: 89.62037029566964 + - type: euclidean_pearson + value: 89.02479391362826 + - type: euclidean_spearman + value: 89.62036733618466 + - type: manhattan_pearson + value: 89.00394756040342 + - type: manhattan_spearman + value: 89.60867744215236 + - task: + type: STS + dataset: + type: mteb/sts16-sts + name: MTEB STS16 + config: default + split: test + revision: 4d8694f8f0e0100860b497b999b3dbed754a0513 + metrics: + - type: cos_sim_pearson + value: 85.08911381280191 + - type: cos_sim_spearman + value: 86.5791780765767 + - type: euclidean_pearson + value: 86.16063473577861 + - type: euclidean_spearman + value: 86.57917745378766 + - type: manhattan_pearson + value: 86.13677924604175 + - type: manhattan_spearman + value: 86.56115615768685 + - task: + type: STS + dataset: + type: mteb/sts17-crosslingual-sts + name: MTEB STS17 (en-en) + config: en-en + split: test + revision: af5e6fb845001ecf41f4c1e033ce921939a2a68d + metrics: + - type: cos_sim_pearson + value: 89.58029496205235 + - type: cos_sim_spearman + value: 89.49551253826998 + - type: euclidean_pearson + value: 90.13714840963748 + - type: euclidean_spearman + value: 89.49551253826998 + - type: manhattan_pearson + value: 90.13039633601363 + - type: manhattan_spearman + value: 89.4513453745516 + - task: + type: STS + dataset: + type: mteb/sts22-crosslingual-sts + name: MTEB STS22 (en) + config: en + split: test + revision: 6d1ba47164174a496b7fa5d3569dae26a6813b80 + metrics: + - type: cos_sim_pearson + value: 69.01546399666435 + - type: cos_sim_spearman + value: 69.33824484595624 + - type: euclidean_pearson + value: 70.76511642998874 + - type: euclidean_spearman + value: 69.33824484595624 + - type: manhattan_pearson + value: 70.84320785047453 + - type: manhattan_spearman + value: 69.54233632223537 + - task: + type: STS + dataset: + type: mteb/stsbenchmark-sts + name: MTEB STSBenchmark + config: default + split: test + revision: b0fddb56ed78048fa8b90373c8a3cfc37b684831 + metrics: + - type: cos_sim_pearson + value: 87.26389196390119 + - type: cos_sim_spearman + value: 89.09721478341385 + - type: euclidean_pearson + value: 88.97208685922517 + - type: euclidean_spearman + value: 89.09720927308881 + - type: manhattan_pearson + value: 88.97513670502573 + - type: manhattan_spearman + value: 89.07647853984004 + - task: + type: Reranking + dataset: + type: mteb/scidocs-reranking + name: MTEB SciDocsRR + config: default + split: test + revision: d3c5e1fc0b855ab6097bf1cda04dd73947d7caab + metrics: + - type: map + value: 87.53075025771936 + - type: mrr + value: 96.24327651288436 + - task: + type: Retrieval + dataset: + type: scifact + name: MTEB SciFact + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 60.428000000000004 + - type: map_at_10 + value: 70.088 + - type: map_at_100 + value: 70.589 + - type: map_at_1000 + value: 70.614 + - type: map_at_3 + value: 67.191 + - type: map_at_5 + value: 68.515 + - type: mrr_at_1 + value: 63.333 + - type: mrr_at_10 + value: 71.13000000000001 + - type: mrr_at_100 + value: 71.545 + - type: mrr_at_1000 + value: 71.569 + - type: mrr_at_3 + value: 68.944 + - type: mrr_at_5 + value: 70.078 + - type: ndcg_at_1 + value: 63.333 + - type: ndcg_at_10 + value: 74.72800000000001 + - type: ndcg_at_100 + value: 76.64999999999999 + - type: ndcg_at_1000 + value: 77.176 + - type: ndcg_at_3 + value: 69.659 + - type: ndcg_at_5 + value: 71.626 + - type: precision_at_1 + value: 63.333 + - type: precision_at_10 + value: 10 + - type: precision_at_100 + value: 1.09 + - type: precision_at_1000 + value: 0.11299999999999999 + - type: precision_at_3 + value: 27.111 + - type: precision_at_5 + value: 17.666999999999998 + - type: recall_at_1 + value: 60.428000000000004 + - type: recall_at_10 + value: 87.98899999999999 + - type: recall_at_100 + value: 96.167 + - type: recall_at_1000 + value: 100 + - type: recall_at_3 + value: 74.006 + - type: recall_at_5 + value: 79.05 + - task: + type: PairClassification + dataset: + type: mteb/sprintduplicatequestions-pairclassification + name: MTEB SprintDuplicateQuestions + config: default + split: test + revision: d66bd1f72af766a5cc4b0ca5e00c162f89e8cc46 + metrics: + - type: cos_sim_accuracy + value: 99.87326732673267 + - type: cos_sim_ap + value: 96.81770773701805 + - type: cos_sim_f1 + value: 93.6318407960199 + - type: cos_sim_precision + value: 93.16831683168317 + - type: cos_sim_recall + value: 94.1 + - type: dot_accuracy + value: 99.87326732673267 + - type: dot_ap + value: 96.8174218946665 + - type: dot_f1 + value: 93.6318407960199 + - type: dot_precision + value: 93.16831683168317 + - type: dot_recall + value: 94.1 + - type: euclidean_accuracy + value: 99.87326732673267 + - type: euclidean_ap + value: 96.81770773701807 + - type: euclidean_f1 + value: 93.6318407960199 + - type: euclidean_precision + value: 93.16831683168317 + - type: euclidean_recall + value: 94.1 + - type: manhattan_accuracy + value: 99.87227722772278 + - type: manhattan_ap + value: 96.83164126821747 + - type: manhattan_f1 + value: 93.54677338669335 + - type: manhattan_precision + value: 93.5935935935936 + - type: manhattan_recall + value: 93.5 + - type: max_accuracy + value: 99.87326732673267 + - type: max_ap + value: 96.83164126821747 + - type: max_f1 + value: 93.6318407960199 + - task: + type: Clustering + dataset: + type: mteb/stackexchange-clustering + name: MTEB StackExchangeClustering + config: default + split: test + revision: 6cbc1f7b2bc0622f2e39d2c77fa502909748c259 + metrics: + - type: v_measure + value: 65.6212042420246 + - task: + type: Clustering + dataset: + type: mteb/stackexchange-clustering-p2p + name: MTEB StackExchangeClusteringP2P + config: default + split: test + revision: 815ca46b2622cec33ccafc3735d572c266efdb44 + metrics: + - type: v_measure + value: 35.779230635982564 + - task: + type: Reranking + dataset: + type: mteb/stackoverflowdupquestions-reranking + name: MTEB StackOverflowDupQuestions + config: default + split: test + revision: e185fbe320c72810689fc5848eb6114e1ef5ec69 + metrics: + - type: map + value: 55.217701909036286 + - type: mrr + value: 56.17658995416349 + - task: + type: Summarization + dataset: + type: mteb/summeval + name: MTEB SummEval + config: default + split: test + revision: cda12ad7615edc362dbf25a00fdd61d3b1eaf93c + metrics: + - type: cos_sim_pearson + value: 30.954206018888453 + - type: cos_sim_spearman + value: 32.71062599450096 + - type: dot_pearson + value: 30.95420929056943 + - type: dot_spearman + value: 32.71062599450096 + - task: + type: Retrieval + dataset: + type: trec-covid + name: MTEB TRECCOVID + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 0.22699999999999998 + - type: map_at_10 + value: 1.924 + - type: map_at_100 + value: 10.525 + - type: map_at_1000 + value: 24.973 + - type: map_at_3 + value: 0.638 + - type: map_at_5 + value: 1.0659999999999998 + - type: mrr_at_1 + value: 84 + - type: mrr_at_10 + value: 91.067 + - type: mrr_at_100 + value: 91.067 + - type: mrr_at_1000 + value: 91.067 + - type: mrr_at_3 + value: 90.667 + - type: mrr_at_5 + value: 91.067 + - type: ndcg_at_1 + value: 81 + - type: ndcg_at_10 + value: 75.566 + - type: ndcg_at_100 + value: 56.387 + - type: ndcg_at_1000 + value: 49.834 + - type: ndcg_at_3 + value: 80.899 + - type: ndcg_at_5 + value: 80.75099999999999 + - type: precision_at_1 + value: 84 + - type: precision_at_10 + value: 79 + - type: precision_at_100 + value: 57.56 + - type: precision_at_1000 + value: 21.8 + - type: precision_at_3 + value: 84.667 + - type: precision_at_5 + value: 85.2 + - type: recall_at_1 + value: 0.22699999999999998 + - type: recall_at_10 + value: 2.136 + - type: recall_at_100 + value: 13.861 + - type: recall_at_1000 + value: 46.299 + - type: recall_at_3 + value: 0.6649999999999999 + - type: recall_at_5 + value: 1.145 + - task: + type: Retrieval + dataset: + type: webis-touche2020 + name: MTEB Touche2020 + config: default + split: test + revision: None + metrics: + - type: map_at_1 + value: 2.752 + - type: map_at_10 + value: 9.951 + - type: map_at_100 + value: 16.794999999999998 + - type: map_at_1000 + value: 18.251 + - type: map_at_3 + value: 5.288 + - type: map_at_5 + value: 6.954000000000001 + - type: mrr_at_1 + value: 38.775999999999996 + - type: mrr_at_10 + value: 50.458000000000006 + - type: mrr_at_100 + value: 51.324999999999996 + - type: mrr_at_1000 + value: 51.339999999999996 + - type: mrr_at_3 + value: 46.939 + - type: mrr_at_5 + value: 47.857 + - type: ndcg_at_1 + value: 36.735 + - type: ndcg_at_10 + value: 25.198999999999998 + - type: ndcg_at_100 + value: 37.938 + - type: ndcg_at_1000 + value: 49.145 + - type: ndcg_at_3 + value: 29.348000000000003 + - type: ndcg_at_5 + value: 25.804 + - type: precision_at_1 + value: 38.775999999999996 + - type: precision_at_10 + value: 22.041 + - type: precision_at_100 + value: 7.939 + - type: precision_at_1000 + value: 1.555 + - type: precision_at_3 + value: 29.932 + - type: precision_at_5 + value: 24.490000000000002 + - type: recall_at_1 + value: 2.752 + - type: recall_at_10 + value: 16.197 + - type: recall_at_100 + value: 49.166 + - type: recall_at_1000 + value: 84.18900000000001 + - type: recall_at_3 + value: 6.438000000000001 + - type: recall_at_5 + value: 9.093 + - task: + type: Classification + dataset: + type: mteb/toxic_conversations_50k + name: MTEB ToxicConversationsClassification + config: default + split: test + revision: d7c0de2777da35d6aae2200a62c6e0e5af397c4c + metrics: + - type: accuracy + value: 71.47980000000001 + - type: ap + value: 14.605194452178754 + - type: f1 + value: 55.07362924988948 + - task: + type: Classification + dataset: + type: mteb/tweet_sentiment_extraction + name: MTEB TweetSentimentExtractionClassification + config: default + split: test + revision: d604517c81ca91fe16a244d1248fc021f9ecee7a + metrics: + - type: accuracy + value: 59.708545557441994 + - type: f1 + value: 60.04751270975683 + - task: + type: Clustering + dataset: + type: mteb/twentynewsgroups-clustering + name: MTEB TwentyNewsgroupsClustering + config: default + split: test + revision: 6125ec4e24fa026cec8a478383ee943acfbd5449 + metrics: + - type: v_measure + value: 53.21105960597211 + - task: + type: PairClassification + dataset: + type: mteb/twittersemeval2015-pairclassification + name: MTEB TwitterSemEval2015 + config: default + split: test + revision: 70970daeab8776df92f5ea462b6173c0b46fd2d1 + metrics: + - type: cos_sim_accuracy + value: 87.58419264469214 + - type: cos_sim_ap + value: 78.55300004517404 + - type: cos_sim_f1 + value: 71.49673530889001 + - type: cos_sim_precision + value: 68.20795400095831 + - type: cos_sim_recall + value: 75.11873350923483 + - type: dot_accuracy + value: 87.58419264469214 + - type: dot_ap + value: 78.55297659559511 + - type: dot_f1 + value: 71.49673530889001 + - type: dot_precision + value: 68.20795400095831 + - type: dot_recall + value: 75.11873350923483 + - type: euclidean_accuracy + value: 87.58419264469214 + - type: euclidean_ap + value: 78.55300477331477 + - type: euclidean_f1 + value: 71.49673530889001 + - type: euclidean_precision + value: 68.20795400095831 + - type: euclidean_recall + value: 75.11873350923483 + - type: manhattan_accuracy + value: 87.5663110210407 + - type: manhattan_ap + value: 78.49982050876562 + - type: manhattan_f1 + value: 71.35488740722104 + - type: manhattan_precision + value: 68.18946862226497 + - type: manhattan_recall + value: 74.82849604221636 + - type: max_accuracy + value: 87.58419264469214 + - type: max_ap + value: 78.55300477331477 + - type: max_f1 + value: 71.49673530889001 + - task: + type: PairClassification + dataset: + type: mteb/twitterurlcorpus-pairclassification + name: MTEB TwitterURLCorpus + config: default + split: test + revision: 8b6510b0b1fa4e4c4f879467980e9be563ec1cdf + metrics: + - type: cos_sim_accuracy + value: 89.09069740365584 + - type: cos_sim_ap + value: 86.22749303724757 + - type: cos_sim_f1 + value: 78.36863452005407 + - type: cos_sim_precision + value: 76.49560117302053 + - type: cos_sim_recall + value: 80.33569448721897 + - type: dot_accuracy + value: 89.09069740365584 + - type: dot_ap + value: 86.22750233655673 + - type: dot_f1 + value: 78.36863452005407 + - type: dot_precision + value: 76.49560117302053 + - type: dot_recall + value: 80.33569448721897 + - type: euclidean_accuracy + value: 89.09069740365584 + - type: euclidean_ap + value: 86.22749355597347 + - type: euclidean_f1 + value: 78.36863452005407 + - type: euclidean_precision + value: 76.49560117302053 + - type: euclidean_recall + value: 80.33569448721897 + - type: manhattan_accuracy + value: 89.08293553770326 + - type: manhattan_ap + value: 86.21913616084771 + - type: manhattan_f1 + value: 78.3907031479847 + - type: manhattan_precision + value: 75.0352013517319 + - type: manhattan_recall + value: 82.06036341238065 + - type: max_accuracy + value: 89.09069740365584 + - type: max_ap + value: 86.22750233655673 + - type: max_f1 + value: 78.3907031479847 +license: apache-2.0 +language: +- en +library_name: sentence-transformers +pipeline_tag: feature-extraction +--- + +

+ +

+ +

+ +

+The crispy sentence embedding family from Mixedbread. +

+ +

+ 🍞 Looking for a simple end-to-end retrieval solution? Meet Omni, our multimodal and multilingual model. Get in touch for access. +

+ + +# mixedbread-ai/mxbai-embed-large-v1 + +Here, we provide several ways to produce sentence embeddings. Please note that you have to provide the prompt `Represent this sentence for searching relevant passages:` for query if you want to use it for retrieval. Besides that you don't need any prompt. Our model also supports [Matryoshka Representation Learning and binary quantization](https://www.mixedbread.ai/blog/binary-mrl). + +## Quickstart + +Here, we provide several ways to produce sentence embeddings. Please note that you have to provide the prompt `Represent this sentence for searching relevant passages: ` for query if you want to use it for retrieval. Besides that you don't need any prompt. + +### sentence-transformers + +``` +python -m pip install -U sentence-transformers +``` + +```python +from sentence_transformers import SentenceTransformer +from sentence_transformers.util import cos_sim +from sentence_transformers.quantization import quantize_embeddings + +# 1. Specify preffered dimensions +dimensions = 512 + +# 2. load model +model = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1", truncate_dim=dimensions) + +# The prompt used for query retrieval tasks: +# query_prompt = 'Represent this sentence for searching relevant passages: ' + +query = "A man is eating a piece of bread" +docs = [ + "A man is eating food.", + "A man is eating pasta.", + "The girl is carrying a baby.", + "A man is riding a horse.", +] + +# 2. Encode +query_embedding = model.encode(query, prompt_name="query") +# Equivalent Alternatives: +# query_embedding = model.encode(query_prompt + query) +# query_embedding = model.encode(query, prompt=query_prompt) + +docs_embeddings = model.encode(docs) + +# Optional: Quantize the embeddings +binary_query_embedding = quantize_embeddings(query_embedding, precision="ubinary") +binary_docs_embeddings = quantize_embeddings(docs_embeddings, precision="ubinary") + +similarities = cos_sim(query_embedding, docs_embeddings) +print('similarities:', similarities) +``` + +### Transformers + +```python +from typing import Dict + +import torch +import numpy as np +from transformers import AutoModel, AutoTokenizer +from sentence_transformers.util import cos_sim + +# For retrieval you need to pass this prompt. Please find our more in our blog post. +def transform_query(query: str) -> str: + """ For retrieval, add the prompt for query (not for documents). + """ + return f'Represent this sentence for searching relevant passages: {query}' + +# The model works really well with cls pooling (default) but also with mean pooling. +def pooling(outputs: torch.Tensor, inputs: Dict, strategy: str = 'cls') -> np.ndarray: + if strategy == 'cls': + outputs = outputs[:, 0] + elif strategy == 'mean': + outputs = torch.sum( + outputs * inputs["attention_mask"][:, :, None], dim=1) / torch.sum(inputs["attention_mask"], dim=1, keepdim=True) + else: + raise NotImplementedError + return outputs.detach().cpu().numpy() + +# 1. load model +model_id = 'mixedbread-ai/mxbai-embed-large-v1' +tokenizer = AutoTokenizer.from_pretrained(model_id) +model = AutoModel.from_pretrained(model_id).cuda() + + +docs = [ + transform_query('A man is eating a piece of bread'), + "A man is eating food.", + "A man is eating pasta.", + "The girl is carrying a baby.", + "A man is riding a horse.", +] + +# 2. encode +inputs = tokenizer(docs, padding=True, return_tensors='pt') +for k, v in inputs.items(): + inputs[k] = v.cuda() +outputs = model(**inputs).last_hidden_state +embeddings = pooling(outputs, inputs, 'cls') + +similarities = cos_sim(embeddings[0], embeddings[1:]) +print('similarities:', similarities) +``` + +### Transformers.js + +If you haven't already, you can install the [Transformers.js](https://huggingface.co/docs/transformers.js) JavaScript library from [NPM](https://www.npmjs.com/package/@xenova/transformers) using: + +``` +npm i @xenova/transformers +``` + +You can then use the model to compute embeddings like this: + +```javascript +import { pipeline, cos_sim } from '@xenova/transformers'; + +// Create a feature extraction pipeline +const extractor = await pipeline('feature-extraction', 'mixedbread-ai/mxbai-embed-large-v1', { + quantized: false, // Comment out this line to use the quantized version +}); + +// Generate sentence embeddings +const docs = [ + 'Represent this sentence for searching relevant passages: A man is eating a piece of bread', + 'A man is eating food.', + 'A man is eating pasta.', + 'The girl is carrying a baby.', + 'A man is riding a horse.', +] +const output = await extractor(docs, { pooling: 'cls' }); + +// Compute similarity scores +const [source_embeddings, ...document_embeddings ] = output.tolist(); +const similarities = document_embeddings.map(x => cos_sim(source_embeddings, x)); +console.log(similarities); // [0.7919578577247139, 0.6369278664248345, 0.16512018371357193, 0.3620778366720027] +``` + +### Using API + +You can use the model via our API as follows: + +```python +from mixedbread_ai.client import MixedbreadAI, EncodingFormat +from sklearn.metrics.pairwise import cosine_similarity +import os + +mxbai = MixedbreadAI(api_key="{MIXEDBREAD_API_KEY}") + +english_sentences = [ + 'What is the capital of Australia?', + 'Canberra is the capital of Australia.' +] + +res = mxbai.embeddings( + input=english_sentences, + model="mixedbread-ai/mxbai-embed-large-v1", + normalized=True, + encoding_format=[EncodingFormat.FLOAT, EncodingFormat.UBINARY, EncodingFormat.INT_8], + dimensions=512 +) + +encoded_embeddings = res.data[0].embedding +print(res.dimensions, encoded_embeddings.ubinary, encoded_embeddings.float_, encoded_embeddings.int_8) +``` + +The API comes with native int8 and binary quantization support! Check out the [docs](https://mixedbread.ai/docs) for more information. + +### Infinity +```bash +docker run --gpus all -v $PWD/data:/app/.cache -p "7997":"7997" \ +michaelf34/infinity:0.0.68 \ +v2 --model-id mixedbread-ai/mxbai-embed-large-v1 --revision "main" --dtype float16 --engine torch --port 7997 +``` + +## Evaluation +As of March 2024, our model archives SOTA performance for Bert-large sized models on the [MTEB](https://huggingface.co/spaces/mteb/leaderboard). It ourperforms commercial models like OpenAIs text-embedding-3-large and matches the performance of model 20x it's size like the [echo-mistral-7b](https://huggingface.co/jspringer/echo-mistral-7b-instruct-lasttoken). Our model was trained with no overlap of the MTEB data, which indicates that our model generalizes well across several domains, tasks and text length. We know there are some limitations with this model, which will be fixed in v2. + + +| Model | Avg (56 datasets) | Classification (12 datasets) | Clustering (11 datasets) | PairClassification (3 datasets) | Reranking (4 datasets) | Retrieval (15 datasets) | STS (10 datasets) | Summarization (1 dataset) | +| --------------------------------------------------------------------------------------------- | ----------------- | ---------------------------- | ------------------------ | ------------------------------- | ---------------------- | ----------------------- | ----------------- | ------------------------- | +| **mxbai-embed-large-v1** | **64.68** | 75.64 | 46.71 | 87.2 | 60.11 | 54.39 | 85.00 | 32.71 | +| [bge-large-en-v1.5](https://huggingface.co/BAAI/bge-large-en-v1.5) | 64.23 | 75.97 | 46.08 | 87.12 | 60.03 | 54.29 | 83.11 | 31.61 | +| [mxbai-embed-2d-large-v1](https://huggingface.co/mixedbread-ai/mxbai-embed-2d-large-v1) | 63.25 | 74.14 | 46.07 | 85.89 | 58.94 | 51.42 | 84.9 | 31.55 | +| [nomic-embed-text-v1](https://huggingface.co/nomic-ai/nomic-embed-text-v1) | 62.39 | 74.12 | 43.91 | 85.15 | 55.69 | 52.81 | 82.06 | 30.08 | +| [jina-embeddings-v2-base-en](https://huggingface.co/jinaai/jina-embeddings-v2-base-en) | 60.38 | 73.45 | 41.73 | 85.38 | 56.98 | 47.87 | 80.7 | 31.6 | +| *Proprietary Models* | | | | | | | | | +| [OpenAI text-embedding-3-large](https://openai.com/blog/new-embedding-models-and-api-updates) | 64.58 | 75.45 | 49.01 | 85.72 | 59.16 | 55.44 | 81.73 | 29.92 | +| [Cohere embed-english-v3.0](https://txt.cohere.com/introducing-embed-v3/) | 64.47 | 76.49 | 47.43 | 85.84 | 58.01 | 55.00 | 82.62 | 30.18 | +| [OpenAI text-embedding-ada-002](https://openai.com/blog/new-and-improved-embedding-model) | 60.99 | 70.93 | 45.90 | 84.89 | 56.32 | 49.25 | 80.97 | 30.80 | + + +Please find more information in our [blog post](https://mixedbread.ai/blog/mxbai-embed-large-v1). + +## Matryoshka and Binary Quantization + +Embeddings in their commonly used form (float arrays) have a high memory footprint when used at scale. Two approaches to solve this problem are Matryoshka Representation Learning (MRL) and (Binary) Quantization. While MRL reduces the number of dimensions of an embedding, binary quantization transforms the value of each dimension from a float32 into a lower precision (int8 or even binary). The model supports both approaches! + +You can also take it one step further, and combine both MRL and quantization. This combination of binary quantization and MRL allows you to reduce the memory usage of your embeddings significantly. This leads to much lower costs when using a vector database in particular. You can read more about the technology and its advantages in our [blog post](https://www.mixedbread.ai/blog/binary-mrl). + +## Community +Please join our [Discord Community](https://discord.gg/jDfMHzAVfU) and share your feedback and thoughts! We are here to help and also always happy to chat. + +## License +Apache 2.0 + +## Citation + +```bibtex +@online{emb2024mxbai, + title={Open Source Strikes Bread - New Fluffy Embeddings Model}, + author={Sean Lee and Aamir Shakir and Darius Koenig and Julius Lipp}, + year={2024}, + url={https://www.mixedbread.ai/blog/mxbai-embed-large-v1}, +} + +@article{li2023angle, + title={AnglE-optimized Text Embeddings}, + author={Li, Xianming and Li, Jing}, + journal={arXiv preprint arXiv:2309.12871}, + year={2023} +} +``` diff --git a/flow-Agent/models/mxbai-embed-large-v1/config.json b/flow-Agent/models/mxbai-embed-large-v1/config.json new file mode 100644 index 0000000..a055edb --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/config.json @@ -0,0 +1,26 @@ +{ + "_name_or_path": "mixedbread-ai/mxbai-embed-large-v1", + "architectures": [ + "BertModel" + ], + "attention_probs_dropout_prob": 0.1, + "classifier_dropout": null, + "gradient_checkpointing": false, + "hidden_act": "gelu", + "hidden_dropout_prob": 0.1, + "hidden_size": 1024, + "initializer_range": 0.02, + "intermediate_size": 4096, + "layer_norm_eps": 1e-12, + "max_position_embeddings": 512, + "model_type": "bert", + "num_attention_heads": 16, + "num_hidden_layers": 24, + "pad_token_id": 0, + "position_embedding_type": "absolute", + "torch_dtype": "float16", + "transformers_version": "4.38.2", + "type_vocab_size": 2, + "use_cache": false, + "vocab_size": 30522 +} diff --git a/flow-Agent/models/mxbai-embed-large-v1/config_sentence_transformers.json b/flow-Agent/models/mxbai-embed-large-v1/config_sentence_transformers.json new file mode 100644 index 0000000..173e6cf --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/config_sentence_transformers.json @@ -0,0 +1,12 @@ +{ + "__version__": { + "sentence_transformers": "2.5.1", + "transformers": "4.37.0", + "pytorch": "2.1.0+cu121" + }, + "prompts": { + "query": "Represent this sentence for searching relevant passages: ", + "passage": "" + }, + "default_prompt_name": null +} \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/gguf/mxbai-embed-large-v1-f16.gguf b/flow-Agent/models/mxbai-embed-large-v1/gguf/mxbai-embed-large-v1-f16.gguf new file mode 100644 index 0000000..a07c052 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/gguf/mxbai-embed-large-v1-f16.gguf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:819c2adf5ce6df2b6bd2ae4ca90d2a69f060afeb438d0c171db57daa02e39c3d +size 669603712 diff --git a/flow-Agent/models/mxbai-embed-large-v1/modules.json b/flow-Agent/models/mxbai-embed-large-v1/modules.json new file mode 100644 index 0000000..f7640f9 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/modules.json @@ -0,0 +1,14 @@ +[ + { + "idx": 0, + "name": "0", + "path": "", + "type": "sentence_transformers.models.Transformer" + }, + { + "idx": 1, + "name": "1", + "path": "1_Pooling", + "type": "sentence_transformers.models.Pooling" + } +] \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/onnx/model.onnx b/flow-Agent/models/mxbai-embed-large-v1/onnx/model.onnx new file mode 100644 index 0000000..1d74693 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/onnx/model.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:adb53ed475faa339bfad3bd2bdb7e6a30b4f47280ade9811f81bef7953f9ab77 +size 1336854282 diff --git a/flow-Agent/models/mxbai-embed-large-v1/onnx/model_fp16.onnx b/flow-Agent/models/mxbai-embed-large-v1/onnx/model_fp16.onnx new file mode 100644 index 0000000..365957d --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/onnx/model_fp16.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b08af11a60452474f6958853f339296f970aac697a49b98da923d0c36cc6c6b1 +size 668828772 diff --git a/flow-Agent/models/mxbai-embed-large-v1/onnx/model_quantized.onnx b/flow-Agent/models/mxbai-embed-large-v1/onnx/model_quantized.onnx new file mode 100644 index 0000000..07ca7ed --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/onnx/model_quantized.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11bda26d2ee754b20d46c90d0fae7eb5a71e0f947e74261afd6ad640ebbcfa7f +size 336983163 diff --git a/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.bin b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.bin new file mode 100644 index 0000000..fc8117c --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2715fe5d778475f06156e6de07353f8e5e73800985159bfd7bf7081c284d87a +size 1336373408 diff --git a/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.xml b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.xml new file mode 100644 index 0000000..c52ea73 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model.xml @@ -0,0 +1,23532 @@ + + + + + + + + -1 + -1 + + + + + + + + -1 + -1 + + + + + + + + -1 + -1 + + + + + + + + 30522 + 1024 + + + + + + + + -1 + -1 + + + + + -1 + -1 + + + + + + + + + + + + + + 30522 + 1024 + + + -1 + -1 + + + + + + -1 + -1 + 1024 + + + + + + + + 2 + 1024 + + + + + + + + -1 + -1 + + + + + -1 + -1 + + + + + + + + + + + + + + 2 + 1024 + + + -1 + -1 + + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 512 + 1024 + + + + + + + + 1 + 512 + + + + + + + + 1 + + + + + + + + -1 + -1 + + + + + 2 + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 1 + + + + + + 1 + + + + + + + + 1 + + + + + + + + 1 + + + + + + + 1 + 512 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + -1 + + + + + + + + 1 + -1 + + + + + 1 + -1 + + + + + + + + + + + + + + 512 + 1024 + + + 1 + -1 + + + + + + 1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + + + + + -1 + -1 + + + + + + -1 + 1 + -1 + + + + + + + + + + + + + -1 + 1 + -1 + + + + + + -1 + 1 + 1 + -1 + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 1 + + + + + + 1 + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + + + + + + + 2 + + + 2 + + + + + + 2 + + + + + + + + 1 + + + 1 + + + 2 + + + + + 4 + + + + + + + + -1 + 1 + 1 + -1 + + + 4 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + -1 + 1 + -1 + -1 + + + 1 + 1 + 1 + 1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + 1 + 1 + 1 + 1 + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + + + + + + + -1 + 1 + -1 + -1 + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.bin b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.bin new file mode 100644 index 0000000..e7d5539 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61df334e52dacadebc1cdadd3974be4ec70a339329830a1df67c7ba4f196c7ae +size 336759312 diff --git a/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.xml b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.xml new file mode 100644 index 0000000..5c387e1 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/openvino/openvino_model_qint8_quantized.xml @@ -0,0 +1,40772 @@ + + + + + + + + -1 + -1 + + + + + + + + -1 + -1 + + + + + + + + -1 + -1 + + + + + + + + 30522 + 1024 + + + + + + + + 30522 + 1024 + + + + + 30522 + 1024 + + + + + + + + 30522 + 1 + + + + + + + + 30522 + 1024 + + + 30522 + 1 + + + + + 30522 + 1024 + + + + + + + + -1 + -1 + + + + + -1 + -1 + + + + + + + + + + + + + + 30522 + 1024 + + + -1 + -1 + + + + + + -1 + -1 + 1024 + + + + + + + + 2 + 1024 + + + + + + + + 2 + 1024 + + + + + 2 + 1024 + + + + + + + + 2 + 1 + + + + + + + + 2 + 1024 + + + 2 + 1 + + + + + 2 + 1024 + + + + + + + + -1 + -1 + + + + + -1 + -1 + + + + + + + + + + + + + + 2 + 1024 + + + -1 + -1 + + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 512 + 1024 + + + + + + + + 512 + 1024 + + + + + 512 + 1024 + + + + + + + + 512 + 1 + + + + + + + + 512 + 1024 + + + 512 + 1 + + + + + 512 + 1024 + + + + + + + + 1 + 512 + + + + + + + + 1 + + + + + + + + -1 + -1 + + + + + 2 + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 1 + + + + + + 1 + + + + + + + + 1 + + + + + + + + 1 + + + + + + + 1 + 512 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + -1 + + + + + + + + 1 + -1 + + + + + 1 + -1 + + + + + + + + + + + + + + 512 + 1024 + + + 1 + -1 + + + + + + 1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + + + + + -1 + -1 + + + + + + -1 + 1 + -1 + + + + + + + + + + + + + -1 + 1 + -1 + + + + + + -1 + 1 + 1 + -1 + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 1 + + + + + + 1 + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + + + + + + + 2 + + + 2 + + + + + + 2 + + + + + + + + 1 + + + 1 + + + 2 + + + + + 4 + + + + + + + + -1 + 1 + 1 + -1 + + + 4 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + -1 + 1 + -1 + -1 + + + 1 + 1 + 1 + 1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + 1 + 1 + 1 + 1 + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + + + + + + + -1 + 1 + -1 + -1 + + + + -1 + 1 + -1 + -1 + + + + + -1 + 1 + -1 + -1 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 4 + + + + + + + + -1 + -1 + 1024 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 4 + + + + + + + -1 + -1 + 16 + 64 + + + 4 + + + + + -1 + 16 + -1 + 64 + + + + + + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 16 + -1 + 64 + + + -1 + 1 + -1 + -1 + + + + + -1 + 16 + -1 + 64 + + + + + + + + 4 + + + + + + + -1 + 16 + -1 + 64 + + + 4 + + + + + -1 + -1 + 16 + 64 + + + + + + + + 3 + + + + + + + + -1 + -1 + 16 + 64 + + + 3 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 1024 + 1024 + + + + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 1024 + + + 1024 + 1 + + + + + 1024 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1024 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 1024 + + + + + + + + + -1 + -1 + 1024 + + + + + + + + 4096 + 1024 + + + + + + + + 4096 + 1024 + + + + + 4096 + 1024 + + + + + + + + 4096 + 1 + + + + + + + + 4096 + 1024 + + + 4096 + 1 + + + + + 4096 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 4096 + 1024 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + 1 + 1 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1 + 1 + 4096 + + + + + -1 + -1 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + -1 + 4096 + + + + + + + + + -1 + -1 + 4096 + + + + + + + + 1024 + 4096 + + + + + + + + 1024 + 4096 + + + + + 1024 + 4096 + + + + + + + + 1024 + 1 + + + + + + + + 1024 + 4096 + + + 1024 + 1 + + + + + 1024 + 4096 + + + + + + + + -1 + -1 + 4096 + + + 1024 + 4096 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + -1 + -1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + + + + + + + + -1 + -1 + 1024 + + + 1 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + + 1 + 1 + 1024 + + + + + + + + -1 + -1 + 1024 + + + 1 + 1 + 1024 + + + + + -1 + -1 + 1024 + + + + + + + -1 + -1 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-Agent/models/mxbai-embed-large-v1/sentence_bert_config.json b/flow-Agent/models/mxbai-embed-large-v1/sentence_bert_config.json new file mode 100644 index 0000000..f789d99 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/sentence_bert_config.json @@ -0,0 +1,4 @@ +{ + "max_seq_length": 512, + "do_lower_case": false +} \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/special_tokens_map.json b/flow-Agent/models/mxbai-embed-large-v1/special_tokens_map.json new file mode 100644 index 0000000..9bbecc1 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/special_tokens_map.json @@ -0,0 +1,37 @@ +{ + "cls_token": { + "content": "[CLS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "mask_token": { + "content": "[MASK]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "pad_token": { + "content": "[PAD]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "sep_token": { + "content": "[SEP]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "unk_token": { + "content": "[UNK]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + } +} diff --git a/flow-Agent/models/mxbai-embed-large-v1/tokenizer.json b/flow-Agent/models/mxbai-embed-large-v1/tokenizer.json new file mode 100644 index 0000000..688882a --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/tokenizer.json @@ -0,0 +1,30672 @@ +{ + "version": "1.0", + "truncation": null, + "padding": null, + "added_tokens": [ + { + "id": 0, + "content": "[PAD]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 100, + "content": "[UNK]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 101, + "content": "[CLS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 102, + "content": "[SEP]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 103, + "content": "[MASK]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + } + ], + "normalizer": { + "type": "BertNormalizer", + "clean_text": true, + "handle_chinese_chars": true, + "strip_accents": null, + "lowercase": true + }, + "pre_tokenizer": { + "type": "BertPreTokenizer" + }, + "post_processor": { + "type": "TemplateProcessing", + "single": [ + { + "SpecialToken": { + "id": "[CLS]", + "type_id": 0 + } + }, + { + "Sequence": { + "id": "A", + "type_id": 0 + } + }, + { + "SpecialToken": { + "id": "[SEP]", + "type_id": 0 + } + } + ], + "pair": [ + { + "SpecialToken": { + "id": "[CLS]", + "type_id": 0 + } + }, + { + "Sequence": { + "id": "A", + "type_id": 0 + } + }, + { + "SpecialToken": { + "id": "[SEP]", + "type_id": 0 + } + }, + { + "Sequence": { + "id": "B", + "type_id": 1 + } + }, + { + "SpecialToken": { + "id": "[SEP]", + "type_id": 1 + } + } + ], + "special_tokens": { + "[CLS]": { + "id": "[CLS]", + "ids": [ + 101 + ], + "tokens": [ + "[CLS]" + ] + }, + "[SEP]": { + "id": "[SEP]", + "ids": [ + 102 + ], + "tokens": [ + "[SEP]" + ] + } + } + }, + "decoder": { + "type": "WordPiece", + "prefix": "##", + "cleanup": true + }, + "model": { + "type": "WordPiece", + "unk_token": "[UNK]", + "continuing_subword_prefix": "##", + "max_input_chars_per_word": 100, + "vocab": { + "[PAD]": 0, + "[unused0]": 1, + "[unused1]": 2, + "[unused2]": 3, + "[unused3]": 4, + "[unused4]": 5, + "[unused5]": 6, + "[unused6]": 7, + "[unused7]": 8, + "[unused8]": 9, + "[unused9]": 10, + "[unused10]": 11, + "[unused11]": 12, + "[unused12]": 13, + "[unused13]": 14, + "[unused14]": 15, + "[unused15]": 16, + "[unused16]": 17, + "[unused17]": 18, + "[unused18]": 19, + "[unused19]": 20, + "[unused20]": 21, + "[unused21]": 22, + "[unused22]": 23, + "[unused23]": 24, + "[unused24]": 25, + "[unused25]": 26, + "[unused26]": 27, + "[unused27]": 28, + "[unused28]": 29, + "[unused29]": 30, + "[unused30]": 31, + "[unused31]": 32, + "[unused32]": 33, + "[unused33]": 34, + "[unused34]": 35, + "[unused35]": 36, + "[unused36]": 37, + "[unused37]": 38, + "[unused38]": 39, + "[unused39]": 40, + "[unused40]": 41, + "[unused41]": 42, + "[unused42]": 43, + "[unused43]": 44, + "[unused44]": 45, + "[unused45]": 46, + "[unused46]": 47, + "[unused47]": 48, + "[unused48]": 49, + "[unused49]": 50, + "[unused50]": 51, + "[unused51]": 52, + "[unused52]": 53, + "[unused53]": 54, + "[unused54]": 55, + "[unused55]": 56, + "[unused56]": 57, + "[unused57]": 58, + "[unused58]": 59, + "[unused59]": 60, + "[unused60]": 61, + "[unused61]": 62, + "[unused62]": 63, + "[unused63]": 64, + "[unused64]": 65, + "[unused65]": 66, + "[unused66]": 67, + "[unused67]": 68, + "[unused68]": 69, + "[unused69]": 70, + "[unused70]": 71, + "[unused71]": 72, + "[unused72]": 73, + "[unused73]": 74, + "[unused74]": 75, + "[unused75]": 76, + "[unused76]": 77, + "[unused77]": 78, + "[unused78]": 79, + "[unused79]": 80, + "[unused80]": 81, + "[unused81]": 82, + "[unused82]": 83, + "[unused83]": 84, + "[unused84]": 85, + "[unused85]": 86, + "[unused86]": 87, + "[unused87]": 88, + "[unused88]": 89, + "[unused89]": 90, + "[unused90]": 91, + "[unused91]": 92, + "[unused92]": 93, + "[unused93]": 94, + "[unused94]": 95, + "[unused95]": 96, + "[unused96]": 97, + "[unused97]": 98, + "[unused98]": 99, + "[UNK]": 100, + "[CLS]": 101, + "[SEP]": 102, + "[MASK]": 103, + "[unused99]": 104, + "[unused100]": 105, + "[unused101]": 106, + "[unused102]": 107, + "[unused103]": 108, + "[unused104]": 109, + "[unused105]": 110, + "[unused106]": 111, + "[unused107]": 112, + "[unused108]": 113, + "[unused109]": 114, + "[unused110]": 115, + "[unused111]": 116, + "[unused112]": 117, + "[unused113]": 118, + "[unused114]": 119, + "[unused115]": 120, + "[unused116]": 121, + "[unused117]": 122, + "[unused118]": 123, + "[unused119]": 124, + "[unused120]": 125, + "[unused121]": 126, + "[unused122]": 127, + "[unused123]": 128, + "[unused124]": 129, + "[unused125]": 130, + "[unused126]": 131, + "[unused127]": 132, + "[unused128]": 133, + "[unused129]": 134, + "[unused130]": 135, + "[unused131]": 136, + "[unused132]": 137, + "[unused133]": 138, + "[unused134]": 139, + "[unused135]": 140, + "[unused136]": 141, + "[unused137]": 142, + "[unused138]": 143, + "[unused139]": 144, + "[unused140]": 145, + "[unused141]": 146, + "[unused142]": 147, + "[unused143]": 148, + "[unused144]": 149, + "[unused145]": 150, + "[unused146]": 151, + "[unused147]": 152, + "[unused148]": 153, + "[unused149]": 154, + "[unused150]": 155, + "[unused151]": 156, + "[unused152]": 157, + "[unused153]": 158, + "[unused154]": 159, + "[unused155]": 160, + "[unused156]": 161, + "[unused157]": 162, + "[unused158]": 163, + "[unused159]": 164, + "[unused160]": 165, + "[unused161]": 166, + "[unused162]": 167, + "[unused163]": 168, + "[unused164]": 169, + "[unused165]": 170, + "[unused166]": 171, + "[unused167]": 172, + "[unused168]": 173, + "[unused169]": 174, + "[unused170]": 175, + "[unused171]": 176, + "[unused172]": 177, + "[unused173]": 178, + "[unused174]": 179, + "[unused175]": 180, + "[unused176]": 181, + "[unused177]": 182, + "[unused178]": 183, + "[unused179]": 184, + "[unused180]": 185, + "[unused181]": 186, + "[unused182]": 187, + "[unused183]": 188, + "[unused184]": 189, + "[unused185]": 190, + "[unused186]": 191, + "[unused187]": 192, + "[unused188]": 193, + "[unused189]": 194, + "[unused190]": 195, + "[unused191]": 196, + "[unused192]": 197, + "[unused193]": 198, + "[unused194]": 199, + "[unused195]": 200, + "[unused196]": 201, + "[unused197]": 202, + "[unused198]": 203, + "[unused199]": 204, + "[unused200]": 205, + "[unused201]": 206, + "[unused202]": 207, + "[unused203]": 208, + "[unused204]": 209, + "[unused205]": 210, + "[unused206]": 211, + "[unused207]": 212, + "[unused208]": 213, + "[unused209]": 214, + "[unused210]": 215, + "[unused211]": 216, + "[unused212]": 217, + "[unused213]": 218, + "[unused214]": 219, + "[unused215]": 220, + "[unused216]": 221, + "[unused217]": 222, + "[unused218]": 223, + "[unused219]": 224, + "[unused220]": 225, + "[unused221]": 226, + "[unused222]": 227, + "[unused223]": 228, + "[unused224]": 229, + "[unused225]": 230, + "[unused226]": 231, + "[unused227]": 232, + "[unused228]": 233, + "[unused229]": 234, + "[unused230]": 235, + "[unused231]": 236, + "[unused232]": 237, + "[unused233]": 238, + "[unused234]": 239, + "[unused235]": 240, + "[unused236]": 241, + "[unused237]": 242, + "[unused238]": 243, + "[unused239]": 244, + "[unused240]": 245, + "[unused241]": 246, + "[unused242]": 247, + "[unused243]": 248, + "[unused244]": 249, + "[unused245]": 250, + "[unused246]": 251, + "[unused247]": 252, + "[unused248]": 253, + "[unused249]": 254, + "[unused250]": 255, + "[unused251]": 256, + "[unused252]": 257, + "[unused253]": 258, + "[unused254]": 259, + "[unused255]": 260, + "[unused256]": 261, + "[unused257]": 262, + "[unused258]": 263, + "[unused259]": 264, + "[unused260]": 265, + "[unused261]": 266, + "[unused262]": 267, + "[unused263]": 268, + "[unused264]": 269, + "[unused265]": 270, + "[unused266]": 271, + "[unused267]": 272, + "[unused268]": 273, + "[unused269]": 274, + "[unused270]": 275, + "[unused271]": 276, + "[unused272]": 277, + "[unused273]": 278, + "[unused274]": 279, + "[unused275]": 280, + "[unused276]": 281, + "[unused277]": 282, + "[unused278]": 283, + "[unused279]": 284, + "[unused280]": 285, + "[unused281]": 286, + "[unused282]": 287, + "[unused283]": 288, + "[unused284]": 289, + "[unused285]": 290, + "[unused286]": 291, + "[unused287]": 292, + "[unused288]": 293, + "[unused289]": 294, + "[unused290]": 295, + "[unused291]": 296, + "[unused292]": 297, + "[unused293]": 298, + "[unused294]": 299, + "[unused295]": 300, + "[unused296]": 301, + "[unused297]": 302, + "[unused298]": 303, + "[unused299]": 304, + "[unused300]": 305, + "[unused301]": 306, + "[unused302]": 307, + "[unused303]": 308, + "[unused304]": 309, + "[unused305]": 310, + "[unused306]": 311, + "[unused307]": 312, + "[unused308]": 313, + "[unused309]": 314, + "[unused310]": 315, + "[unused311]": 316, + "[unused312]": 317, + "[unused313]": 318, + "[unused314]": 319, + "[unused315]": 320, + "[unused316]": 321, + "[unused317]": 322, + "[unused318]": 323, + "[unused319]": 324, + "[unused320]": 325, + "[unused321]": 326, + "[unused322]": 327, + "[unused323]": 328, + "[unused324]": 329, + "[unused325]": 330, + "[unused326]": 331, + "[unused327]": 332, + "[unused328]": 333, + "[unused329]": 334, + "[unused330]": 335, + "[unused331]": 336, + "[unused332]": 337, + "[unused333]": 338, + "[unused334]": 339, + "[unused335]": 340, + "[unused336]": 341, + "[unused337]": 342, + "[unused338]": 343, + "[unused339]": 344, + "[unused340]": 345, + "[unused341]": 346, + "[unused342]": 347, + "[unused343]": 348, + "[unused344]": 349, + "[unused345]": 350, + "[unused346]": 351, + "[unused347]": 352, + "[unused348]": 353, + "[unused349]": 354, + "[unused350]": 355, + "[unused351]": 356, + "[unused352]": 357, + "[unused353]": 358, + "[unused354]": 359, + "[unused355]": 360, + "[unused356]": 361, + "[unused357]": 362, + "[unused358]": 363, + "[unused359]": 364, + "[unused360]": 365, + "[unused361]": 366, + "[unused362]": 367, + "[unused363]": 368, + "[unused364]": 369, + "[unused365]": 370, + "[unused366]": 371, + "[unused367]": 372, + "[unused368]": 373, + "[unused369]": 374, + "[unused370]": 375, + "[unused371]": 376, + "[unused372]": 377, + "[unused373]": 378, + "[unused374]": 379, + "[unused375]": 380, + "[unused376]": 381, + "[unused377]": 382, + "[unused378]": 383, + "[unused379]": 384, + "[unused380]": 385, + "[unused381]": 386, + "[unused382]": 387, + "[unused383]": 388, + "[unused384]": 389, + "[unused385]": 390, + "[unused386]": 391, + "[unused387]": 392, + "[unused388]": 393, + "[unused389]": 394, + "[unused390]": 395, + "[unused391]": 396, + "[unused392]": 397, + "[unused393]": 398, + "[unused394]": 399, + "[unused395]": 400, + "[unused396]": 401, + "[unused397]": 402, + "[unused398]": 403, + "[unused399]": 404, + "[unused400]": 405, + "[unused401]": 406, + "[unused402]": 407, + "[unused403]": 408, + "[unused404]": 409, + "[unused405]": 410, + "[unused406]": 411, + "[unused407]": 412, + "[unused408]": 413, + "[unused409]": 414, + "[unused410]": 415, + "[unused411]": 416, + "[unused412]": 417, + "[unused413]": 418, + "[unused414]": 419, + "[unused415]": 420, + "[unused416]": 421, + "[unused417]": 422, + "[unused418]": 423, + "[unused419]": 424, + "[unused420]": 425, + "[unused421]": 426, + "[unused422]": 427, + "[unused423]": 428, + "[unused424]": 429, + "[unused425]": 430, + "[unused426]": 431, + "[unused427]": 432, + "[unused428]": 433, + "[unused429]": 434, + "[unused430]": 435, + "[unused431]": 436, + "[unused432]": 437, + "[unused433]": 438, + "[unused434]": 439, + "[unused435]": 440, + "[unused436]": 441, + "[unused437]": 442, + "[unused438]": 443, + "[unused439]": 444, + "[unused440]": 445, + "[unused441]": 446, + "[unused442]": 447, + "[unused443]": 448, + "[unused444]": 449, + "[unused445]": 450, + "[unused446]": 451, + "[unused447]": 452, + "[unused448]": 453, + "[unused449]": 454, + "[unused450]": 455, + "[unused451]": 456, + "[unused452]": 457, + "[unused453]": 458, + "[unused454]": 459, + "[unused455]": 460, + "[unused456]": 461, + "[unused457]": 462, + "[unused458]": 463, + "[unused459]": 464, + "[unused460]": 465, + "[unused461]": 466, + "[unused462]": 467, + "[unused463]": 468, + "[unused464]": 469, + "[unused465]": 470, + "[unused466]": 471, + "[unused467]": 472, + "[unused468]": 473, + "[unused469]": 474, + "[unused470]": 475, + "[unused471]": 476, + "[unused472]": 477, + "[unused473]": 478, + "[unused474]": 479, + "[unused475]": 480, + "[unused476]": 481, + "[unused477]": 482, + "[unused478]": 483, + "[unused479]": 484, + "[unused480]": 485, + "[unused481]": 486, + "[unused482]": 487, + "[unused483]": 488, + "[unused484]": 489, + "[unused485]": 490, + "[unused486]": 491, + "[unused487]": 492, + "[unused488]": 493, + "[unused489]": 494, + "[unused490]": 495, + "[unused491]": 496, + "[unused492]": 497, + "[unused493]": 498, + "[unused494]": 499, + "[unused495]": 500, + "[unused496]": 501, + "[unused497]": 502, + "[unused498]": 503, + "[unused499]": 504, + "[unused500]": 505, + "[unused501]": 506, + "[unused502]": 507, + "[unused503]": 508, + "[unused504]": 509, + "[unused505]": 510, + "[unused506]": 511, + "[unused507]": 512, + "[unused508]": 513, + "[unused509]": 514, + "[unused510]": 515, + "[unused511]": 516, + "[unused512]": 517, + "[unused513]": 518, + "[unused514]": 519, + "[unused515]": 520, + "[unused516]": 521, + "[unused517]": 522, + "[unused518]": 523, + "[unused519]": 524, + "[unused520]": 525, + "[unused521]": 526, + "[unused522]": 527, + "[unused523]": 528, + "[unused524]": 529, + "[unused525]": 530, + "[unused526]": 531, + "[unused527]": 532, + "[unused528]": 533, + "[unused529]": 534, + "[unused530]": 535, + "[unused531]": 536, + "[unused532]": 537, + "[unused533]": 538, + "[unused534]": 539, + "[unused535]": 540, + "[unused536]": 541, + "[unused537]": 542, + "[unused538]": 543, + "[unused539]": 544, + "[unused540]": 545, + "[unused541]": 546, + "[unused542]": 547, + "[unused543]": 548, + "[unused544]": 549, + "[unused545]": 550, + "[unused546]": 551, + "[unused547]": 552, + "[unused548]": 553, + "[unused549]": 554, + "[unused550]": 555, + "[unused551]": 556, + "[unused552]": 557, + "[unused553]": 558, + "[unused554]": 559, + "[unused555]": 560, + "[unused556]": 561, + "[unused557]": 562, + "[unused558]": 563, + "[unused559]": 564, + "[unused560]": 565, + "[unused561]": 566, + "[unused562]": 567, + "[unused563]": 568, + "[unused564]": 569, + "[unused565]": 570, + "[unused566]": 571, + "[unused567]": 572, + "[unused568]": 573, + "[unused569]": 574, + "[unused570]": 575, + "[unused571]": 576, + "[unused572]": 577, + "[unused573]": 578, + "[unused574]": 579, + "[unused575]": 580, + "[unused576]": 581, + "[unused577]": 582, + "[unused578]": 583, + "[unused579]": 584, + "[unused580]": 585, + "[unused581]": 586, + "[unused582]": 587, + "[unused583]": 588, + "[unused584]": 589, + "[unused585]": 590, + "[unused586]": 591, + "[unused587]": 592, + "[unused588]": 593, + "[unused589]": 594, + "[unused590]": 595, + "[unused591]": 596, + "[unused592]": 597, + "[unused593]": 598, + "[unused594]": 599, + "[unused595]": 600, + "[unused596]": 601, + "[unused597]": 602, + "[unused598]": 603, + "[unused599]": 604, + "[unused600]": 605, + "[unused601]": 606, + "[unused602]": 607, + "[unused603]": 608, + "[unused604]": 609, + "[unused605]": 610, + "[unused606]": 611, + "[unused607]": 612, + "[unused608]": 613, + "[unused609]": 614, + "[unused610]": 615, + "[unused611]": 616, + "[unused612]": 617, + "[unused613]": 618, + "[unused614]": 619, + "[unused615]": 620, + "[unused616]": 621, + "[unused617]": 622, + "[unused618]": 623, + "[unused619]": 624, + "[unused620]": 625, + "[unused621]": 626, + "[unused622]": 627, + "[unused623]": 628, + "[unused624]": 629, + "[unused625]": 630, + "[unused626]": 631, + "[unused627]": 632, + "[unused628]": 633, + "[unused629]": 634, + "[unused630]": 635, + "[unused631]": 636, + "[unused632]": 637, + "[unused633]": 638, + "[unused634]": 639, + "[unused635]": 640, + "[unused636]": 641, + "[unused637]": 642, + "[unused638]": 643, + "[unused639]": 644, + "[unused640]": 645, + "[unused641]": 646, + "[unused642]": 647, + "[unused643]": 648, + "[unused644]": 649, + "[unused645]": 650, + "[unused646]": 651, + "[unused647]": 652, + "[unused648]": 653, + "[unused649]": 654, + "[unused650]": 655, + "[unused651]": 656, + "[unused652]": 657, + "[unused653]": 658, + "[unused654]": 659, + "[unused655]": 660, + "[unused656]": 661, + "[unused657]": 662, + "[unused658]": 663, + "[unused659]": 664, + "[unused660]": 665, + "[unused661]": 666, + "[unused662]": 667, + "[unused663]": 668, + "[unused664]": 669, + "[unused665]": 670, + "[unused666]": 671, + "[unused667]": 672, + "[unused668]": 673, + "[unused669]": 674, + "[unused670]": 675, + "[unused671]": 676, + "[unused672]": 677, + "[unused673]": 678, + "[unused674]": 679, + "[unused675]": 680, + "[unused676]": 681, + "[unused677]": 682, + "[unused678]": 683, + "[unused679]": 684, + "[unused680]": 685, + "[unused681]": 686, + "[unused682]": 687, + "[unused683]": 688, + "[unused684]": 689, + "[unused685]": 690, + "[unused686]": 691, + "[unused687]": 692, + "[unused688]": 693, + "[unused689]": 694, + "[unused690]": 695, + "[unused691]": 696, + "[unused692]": 697, + "[unused693]": 698, + "[unused694]": 699, + "[unused695]": 700, + "[unused696]": 701, + "[unused697]": 702, + "[unused698]": 703, + "[unused699]": 704, + "[unused700]": 705, + "[unused701]": 706, + "[unused702]": 707, + "[unused703]": 708, + "[unused704]": 709, + "[unused705]": 710, + "[unused706]": 711, + "[unused707]": 712, + "[unused708]": 713, + "[unused709]": 714, + "[unused710]": 715, + "[unused711]": 716, + "[unused712]": 717, + "[unused713]": 718, + "[unused714]": 719, + "[unused715]": 720, + "[unused716]": 721, + "[unused717]": 722, + "[unused718]": 723, + "[unused719]": 724, + "[unused720]": 725, + "[unused721]": 726, + "[unused722]": 727, + "[unused723]": 728, + "[unused724]": 729, + "[unused725]": 730, + "[unused726]": 731, + "[unused727]": 732, + "[unused728]": 733, + "[unused729]": 734, + "[unused730]": 735, + "[unused731]": 736, + "[unused732]": 737, + "[unused733]": 738, + "[unused734]": 739, + "[unused735]": 740, + "[unused736]": 741, + "[unused737]": 742, + "[unused738]": 743, + "[unused739]": 744, + "[unused740]": 745, + "[unused741]": 746, + "[unused742]": 747, + "[unused743]": 748, + "[unused744]": 749, + "[unused745]": 750, + "[unused746]": 751, + "[unused747]": 752, + "[unused748]": 753, + "[unused749]": 754, + "[unused750]": 755, + "[unused751]": 756, + "[unused752]": 757, + "[unused753]": 758, + "[unused754]": 759, + "[unused755]": 760, + "[unused756]": 761, + "[unused757]": 762, + "[unused758]": 763, + "[unused759]": 764, + "[unused760]": 765, + "[unused761]": 766, + "[unused762]": 767, + "[unused763]": 768, + "[unused764]": 769, + "[unused765]": 770, + "[unused766]": 771, + "[unused767]": 772, + "[unused768]": 773, + "[unused769]": 774, + "[unused770]": 775, + "[unused771]": 776, + "[unused772]": 777, + "[unused773]": 778, + "[unused774]": 779, + "[unused775]": 780, + "[unused776]": 781, + "[unused777]": 782, + "[unused778]": 783, + "[unused779]": 784, + "[unused780]": 785, + "[unused781]": 786, + "[unused782]": 787, + "[unused783]": 788, + "[unused784]": 789, + "[unused785]": 790, + "[unused786]": 791, + "[unused787]": 792, + "[unused788]": 793, + "[unused789]": 794, + "[unused790]": 795, + "[unused791]": 796, + "[unused792]": 797, + "[unused793]": 798, + "[unused794]": 799, + "[unused795]": 800, + "[unused796]": 801, + "[unused797]": 802, + "[unused798]": 803, + "[unused799]": 804, + "[unused800]": 805, + "[unused801]": 806, + "[unused802]": 807, + "[unused803]": 808, + "[unused804]": 809, + "[unused805]": 810, + "[unused806]": 811, + "[unused807]": 812, + "[unused808]": 813, + "[unused809]": 814, + "[unused810]": 815, + "[unused811]": 816, + "[unused812]": 817, + "[unused813]": 818, + "[unused814]": 819, + "[unused815]": 820, + "[unused816]": 821, + "[unused817]": 822, + "[unused818]": 823, + "[unused819]": 824, + "[unused820]": 825, + "[unused821]": 826, + "[unused822]": 827, + "[unused823]": 828, + "[unused824]": 829, + "[unused825]": 830, + "[unused826]": 831, + "[unused827]": 832, + "[unused828]": 833, + "[unused829]": 834, + "[unused830]": 835, + "[unused831]": 836, + "[unused832]": 837, + "[unused833]": 838, + "[unused834]": 839, + "[unused835]": 840, + "[unused836]": 841, + "[unused837]": 842, + "[unused838]": 843, + "[unused839]": 844, + "[unused840]": 845, + "[unused841]": 846, + "[unused842]": 847, + "[unused843]": 848, + "[unused844]": 849, + "[unused845]": 850, + "[unused846]": 851, + "[unused847]": 852, + "[unused848]": 853, + "[unused849]": 854, + "[unused850]": 855, + "[unused851]": 856, + "[unused852]": 857, + "[unused853]": 858, + "[unused854]": 859, + "[unused855]": 860, + "[unused856]": 861, + "[unused857]": 862, + "[unused858]": 863, + "[unused859]": 864, + "[unused860]": 865, + "[unused861]": 866, + "[unused862]": 867, + "[unused863]": 868, + "[unused864]": 869, + "[unused865]": 870, + "[unused866]": 871, + "[unused867]": 872, + "[unused868]": 873, + "[unused869]": 874, + "[unused870]": 875, + "[unused871]": 876, + "[unused872]": 877, + "[unused873]": 878, + "[unused874]": 879, + "[unused875]": 880, + "[unused876]": 881, + "[unused877]": 882, + "[unused878]": 883, + "[unused879]": 884, + "[unused880]": 885, + "[unused881]": 886, + "[unused882]": 887, + "[unused883]": 888, + "[unused884]": 889, + "[unused885]": 890, + "[unused886]": 891, + "[unused887]": 892, + "[unused888]": 893, + "[unused889]": 894, + "[unused890]": 895, + "[unused891]": 896, + "[unused892]": 897, + "[unused893]": 898, + "[unused894]": 899, + "[unused895]": 900, + "[unused896]": 901, + "[unused897]": 902, + "[unused898]": 903, + "[unused899]": 904, + "[unused900]": 905, + "[unused901]": 906, + "[unused902]": 907, + "[unused903]": 908, + "[unused904]": 909, + "[unused905]": 910, + "[unused906]": 911, + "[unused907]": 912, + "[unused908]": 913, + "[unused909]": 914, + "[unused910]": 915, + "[unused911]": 916, + "[unused912]": 917, + "[unused913]": 918, + "[unused914]": 919, + "[unused915]": 920, + "[unused916]": 921, + "[unused917]": 922, + "[unused918]": 923, + "[unused919]": 924, + "[unused920]": 925, + "[unused921]": 926, + "[unused922]": 927, + "[unused923]": 928, + "[unused924]": 929, + "[unused925]": 930, + "[unused926]": 931, + "[unused927]": 932, + "[unused928]": 933, + "[unused929]": 934, + "[unused930]": 935, + "[unused931]": 936, + "[unused932]": 937, + "[unused933]": 938, + "[unused934]": 939, + "[unused935]": 940, + "[unused936]": 941, + "[unused937]": 942, + "[unused938]": 943, + "[unused939]": 944, + "[unused940]": 945, + "[unused941]": 946, + "[unused942]": 947, + "[unused943]": 948, + "[unused944]": 949, + "[unused945]": 950, + "[unused946]": 951, + "[unused947]": 952, + "[unused948]": 953, + "[unused949]": 954, + "[unused950]": 955, + "[unused951]": 956, + "[unused952]": 957, + "[unused953]": 958, + "[unused954]": 959, + "[unused955]": 960, + "[unused956]": 961, + "[unused957]": 962, + "[unused958]": 963, + "[unused959]": 964, + "[unused960]": 965, + "[unused961]": 966, + "[unused962]": 967, + "[unused963]": 968, + "[unused964]": 969, + "[unused965]": 970, + "[unused966]": 971, + "[unused967]": 972, + "[unused968]": 973, + "[unused969]": 974, + "[unused970]": 975, + "[unused971]": 976, + "[unused972]": 977, + "[unused973]": 978, + "[unused974]": 979, + "[unused975]": 980, + "[unused976]": 981, + "[unused977]": 982, + "[unused978]": 983, + "[unused979]": 984, + "[unused980]": 985, + "[unused981]": 986, + "[unused982]": 987, + "[unused983]": 988, + "[unused984]": 989, + "[unused985]": 990, + "[unused986]": 991, + "[unused987]": 992, + "[unused988]": 993, + "[unused989]": 994, + "[unused990]": 995, + "[unused991]": 996, + "[unused992]": 997, + "[unused993]": 998, + "!": 999, + "\"": 1000, + "#": 1001, + "$": 1002, + "%": 1003, + "&": 1004, + "'": 1005, + "(": 1006, + ")": 1007, + "*": 1008, + "+": 1009, + ",": 1010, + "-": 1011, + ".": 1012, + "/": 1013, + "0": 1014, + "1": 1015, + "2": 1016, + "3": 1017, + "4": 1018, + "5": 1019, + "6": 1020, + "7": 1021, + "8": 1022, + "9": 1023, + ":": 1024, + ";": 1025, + "<": 1026, + "=": 1027, + ">": 1028, + "?": 1029, + "@": 1030, + "[": 1031, + "\\": 1032, + "]": 1033, + "^": 1034, + "_": 1035, + "`": 1036, + "a": 1037, + "b": 1038, + "c": 1039, + "d": 1040, + "e": 1041, + "f": 1042, + "g": 1043, + "h": 1044, + "i": 1045, + "j": 1046, + "k": 1047, + "l": 1048, + "m": 1049, + "n": 1050, + "o": 1051, + "p": 1052, + "q": 1053, + "r": 1054, + "s": 1055, + "t": 1056, + "u": 1057, + "v": 1058, + "w": 1059, + "x": 1060, + "y": 1061, + "z": 1062, + "{": 1063, + "|": 1064, + "}": 1065, + "~": 1066, + "¡": 1067, + "¢": 1068, + "£": 1069, + "¤": 1070, + "¥": 1071, + "¦": 1072, + "§": 1073, + "¨": 1074, + "©": 1075, + "ª": 1076, + "«": 1077, + "¬": 1078, + "®": 1079, + "°": 1080, + "±": 1081, + "²": 1082, + "³": 1083, + "´": 1084, + "µ": 1085, + "¶": 1086, + "·": 1087, + "¹": 1088, + "º": 1089, + "»": 1090, + "¼": 1091, + "½": 1092, + "¾": 1093, + "¿": 1094, + "×": 1095, + "ß": 1096, + "æ": 1097, + "ð": 1098, + "÷": 1099, + "ø": 1100, + "þ": 1101, + "đ": 1102, + "ħ": 1103, + "ı": 1104, + "ł": 1105, + "ŋ": 1106, + "œ": 1107, + "ƒ": 1108, + "ɐ": 1109, + "ɑ": 1110, + "ɒ": 1111, + "ɔ": 1112, + "ɕ": 1113, + "ə": 1114, + "ɛ": 1115, + "ɡ": 1116, + "ɣ": 1117, + "ɨ": 1118, + "ɪ": 1119, + "ɫ": 1120, + "ɬ": 1121, + "ɯ": 1122, + "ɲ": 1123, + "ɴ": 1124, + "ɹ": 1125, + "ɾ": 1126, + "ʀ": 1127, + "ʁ": 1128, + "ʂ": 1129, + "ʃ": 1130, + "ʉ": 1131, + "ʊ": 1132, + "ʋ": 1133, + "ʌ": 1134, + "ʎ": 1135, + "ʐ": 1136, + "ʑ": 1137, + "ʒ": 1138, + "ʔ": 1139, + "ʰ": 1140, + "ʲ": 1141, + "ʳ": 1142, + "ʷ": 1143, + "ʸ": 1144, + "ʻ": 1145, + "ʼ": 1146, + "ʾ": 1147, + "ʿ": 1148, + "ˈ": 1149, + "ː": 1150, + "ˡ": 1151, + "ˢ": 1152, + "ˣ": 1153, + "ˤ": 1154, + "α": 1155, + "β": 1156, + "γ": 1157, + "δ": 1158, + "ε": 1159, + "ζ": 1160, + "η": 1161, + "θ": 1162, + "ι": 1163, + "κ": 1164, + "λ": 1165, + "μ": 1166, + "ν": 1167, + "ξ": 1168, + "ο": 1169, + "π": 1170, + "ρ": 1171, + "ς": 1172, + "σ": 1173, + "τ": 1174, + "υ": 1175, + "φ": 1176, + "χ": 1177, + "ψ": 1178, + "ω": 1179, + "а": 1180, + "б": 1181, + "в": 1182, + "г": 1183, + "д": 1184, + "е": 1185, + "ж": 1186, + "з": 1187, + "и": 1188, + "к": 1189, + "л": 1190, + "м": 1191, + "н": 1192, + "о": 1193, + "п": 1194, + "р": 1195, + "с": 1196, + "т": 1197, + "у": 1198, + "ф": 1199, + "х": 1200, + "ц": 1201, + "ч": 1202, + "ш": 1203, + "щ": 1204, + "ъ": 1205, + "ы": 1206, + "ь": 1207, + "э": 1208, + "ю": 1209, + "я": 1210, + "ђ": 1211, + "є": 1212, + "і": 1213, + "ј": 1214, + "љ": 1215, + "њ": 1216, + "ћ": 1217, + "ӏ": 1218, + "ա": 1219, + "բ": 1220, + "գ": 1221, + "դ": 1222, + "ե": 1223, + "թ": 1224, + "ի": 1225, + "լ": 1226, + "կ": 1227, + "հ": 1228, + "մ": 1229, + "յ": 1230, + "ն": 1231, + "ո": 1232, + "պ": 1233, + "ս": 1234, + "վ": 1235, + "տ": 1236, + "ր": 1237, + "ւ": 1238, + "ք": 1239, + "־": 1240, + "א": 1241, + "ב": 1242, + "ג": 1243, + "ד": 1244, + "ה": 1245, + "ו": 1246, + "ז": 1247, + "ח": 1248, + "ט": 1249, + "י": 1250, + "ך": 1251, + "כ": 1252, + "ל": 1253, + "ם": 1254, + "מ": 1255, + "ן": 1256, + "נ": 1257, + "ס": 1258, + "ע": 1259, + "ף": 1260, + "פ": 1261, + "ץ": 1262, + "צ": 1263, + "ק": 1264, + "ר": 1265, + "ש": 1266, + "ת": 1267, + "،": 1268, + "ء": 1269, + "ا": 1270, + "ب": 1271, + "ة": 1272, + "ت": 1273, + "ث": 1274, + "ج": 1275, + "ح": 1276, + "خ": 1277, + "د": 1278, + "ذ": 1279, + "ر": 1280, + "ز": 1281, + "س": 1282, + "ش": 1283, + "ص": 1284, + "ض": 1285, + "ط": 1286, + "ظ": 1287, + "ع": 1288, + "غ": 1289, + "ـ": 1290, + "ف": 1291, + "ق": 1292, + "ك": 1293, + "ل": 1294, + "م": 1295, + "ن": 1296, + "ه": 1297, + "و": 1298, + "ى": 1299, + "ي": 1300, + "ٹ": 1301, + "پ": 1302, + "چ": 1303, + "ک": 1304, + "گ": 1305, + "ں": 1306, + "ھ": 1307, + "ہ": 1308, + "ی": 1309, + "ے": 1310, + "अ": 1311, + "आ": 1312, + "उ": 1313, + "ए": 1314, + "क": 1315, + "ख": 1316, + "ग": 1317, + "च": 1318, + "ज": 1319, + "ट": 1320, + "ड": 1321, + "ण": 1322, + "त": 1323, + "थ": 1324, + "द": 1325, + "ध": 1326, + "न": 1327, + "प": 1328, + "ब": 1329, + "भ": 1330, + "म": 1331, + "य": 1332, + "र": 1333, + "ल": 1334, + "व": 1335, + "श": 1336, + "ष": 1337, + "स": 1338, + "ह": 1339, + "ा": 1340, + "ि": 1341, + "ी": 1342, + "ो": 1343, + "।": 1344, + "॥": 1345, + "ং": 1346, + "অ": 1347, + "আ": 1348, + "ই": 1349, + "উ": 1350, + "এ": 1351, + "ও": 1352, + "ক": 1353, + "খ": 1354, + "গ": 1355, + "চ": 1356, + "ছ": 1357, + "জ": 1358, + "ট": 1359, + "ড": 1360, + "ণ": 1361, + "ত": 1362, + "থ": 1363, + "দ": 1364, + "ধ": 1365, + "ন": 1366, + "প": 1367, + "ব": 1368, + "ভ": 1369, + "ম": 1370, + "য": 1371, + "র": 1372, + "ল": 1373, + "শ": 1374, + "ষ": 1375, + "স": 1376, + "হ": 1377, + "া": 1378, + "ি": 1379, + "ী": 1380, + "ে": 1381, + "க": 1382, + "ச": 1383, + "ட": 1384, + "த": 1385, + "ந": 1386, + "ன": 1387, + "ப": 1388, + "ம": 1389, + "ய": 1390, + "ர": 1391, + "ல": 1392, + "ள": 1393, + "வ": 1394, + "ா": 1395, + "ி": 1396, + "ு": 1397, + "ே": 1398, + "ை": 1399, + "ನ": 1400, + "ರ": 1401, + "ಾ": 1402, + "ක": 1403, + "ය": 1404, + "ර": 1405, + "ල": 1406, + "ව": 1407, + "ා": 1408, + "ก": 1409, + "ง": 1410, + "ต": 1411, + "ท": 1412, + "น": 1413, + "พ": 1414, + "ม": 1415, + "ย": 1416, + "ร": 1417, + "ล": 1418, + "ว": 1419, + "ส": 1420, + "อ": 1421, + "า": 1422, + "เ": 1423, + "་": 1424, + "།": 1425, + "ག": 1426, + "ང": 1427, + "ད": 1428, + "ན": 1429, + "པ": 1430, + "བ": 1431, + "མ": 1432, + "འ": 1433, + "ར": 1434, + "ལ": 1435, + "ས": 1436, + "မ": 1437, + "ა": 1438, + "ბ": 1439, + "გ": 1440, + "დ": 1441, + "ე": 1442, + "ვ": 1443, + "თ": 1444, + "ი": 1445, + "კ": 1446, + "ლ": 1447, + "მ": 1448, + "ნ": 1449, + "ო": 1450, + "რ": 1451, + "ს": 1452, + "ტ": 1453, + "უ": 1454, + "ᄀ": 1455, + "ᄂ": 1456, + "ᄃ": 1457, + "ᄅ": 1458, + "ᄆ": 1459, + "ᄇ": 1460, + "ᄉ": 1461, + "ᄊ": 1462, + "ᄋ": 1463, + "ᄌ": 1464, + "ᄎ": 1465, + "ᄏ": 1466, + "ᄐ": 1467, + "ᄑ": 1468, + "ᄒ": 1469, + "ᅡ": 1470, + "ᅢ": 1471, + "ᅥ": 1472, + "ᅦ": 1473, + "ᅧ": 1474, + "ᅩ": 1475, + "ᅪ": 1476, + "ᅭ": 1477, + "ᅮ": 1478, + "ᅯ": 1479, + "ᅲ": 1480, + "ᅳ": 1481, + "ᅴ": 1482, + "ᅵ": 1483, + "ᆨ": 1484, + "ᆫ": 1485, + "ᆯ": 1486, + "ᆷ": 1487, + "ᆸ": 1488, + "ᆼ": 1489, + "ᴬ": 1490, + "ᴮ": 1491, + "ᴰ": 1492, + "ᴵ": 1493, + "ᴺ": 1494, + "ᵀ": 1495, + "ᵃ": 1496, + "ᵇ": 1497, + "ᵈ": 1498, + "ᵉ": 1499, + "ᵍ": 1500, + "ᵏ": 1501, + "ᵐ": 1502, + "ᵒ": 1503, + "ᵖ": 1504, + "ᵗ": 1505, + "ᵘ": 1506, + "ᵢ": 1507, + "ᵣ": 1508, + "ᵤ": 1509, + "ᵥ": 1510, + "ᶜ": 1511, + "ᶠ": 1512, + "‐": 1513, + "‑": 1514, + "‒": 1515, + "–": 1516, + "—": 1517, + "―": 1518, + "‖": 1519, + "‘": 1520, + "’": 1521, + "‚": 1522, + "“": 1523, + "”": 1524, + "„": 1525, + "†": 1526, + "‡": 1527, + "•": 1528, + "…": 1529, + "‰": 1530, + "′": 1531, + "″": 1532, + "›": 1533, + "‿": 1534, + "⁄": 1535, + "⁰": 1536, + "ⁱ": 1537, + "⁴": 1538, + "⁵": 1539, + "⁶": 1540, + "⁷": 1541, + "⁸": 1542, + "⁹": 1543, + "⁺": 1544, + "⁻": 1545, + "ⁿ": 1546, + "₀": 1547, + "₁": 1548, + "₂": 1549, + "₃": 1550, + "₄": 1551, + "₅": 1552, + "₆": 1553, + "₇": 1554, + "₈": 1555, + "₉": 1556, + "₊": 1557, + "₍": 1558, + "₎": 1559, + "ₐ": 1560, + "ₑ": 1561, + "ₒ": 1562, + "ₓ": 1563, + "ₕ": 1564, + "ₖ": 1565, + "ₗ": 1566, + "ₘ": 1567, + "ₙ": 1568, + "ₚ": 1569, + "ₛ": 1570, + "ₜ": 1571, + "₤": 1572, + "₩": 1573, + "€": 1574, + "₱": 1575, + "₹": 1576, + "ℓ": 1577, + "№": 1578, + "ℝ": 1579, + "™": 1580, + "⅓": 1581, + "⅔": 1582, + "←": 1583, + "↑": 1584, + "→": 1585, + "↓": 1586, + "↔": 1587, + "↦": 1588, + "⇄": 1589, + "⇌": 1590, + "⇒": 1591, + "∂": 1592, + "∅": 1593, + "∆": 1594, + "∇": 1595, + "∈": 1596, + "−": 1597, + "∗": 1598, + "∘": 1599, + "√": 1600, + "∞": 1601, + "∧": 1602, + "∨": 1603, + "∩": 1604, + "∪": 1605, + "≈": 1606, + "≡": 1607, + "≤": 1608, + "≥": 1609, + "⊂": 1610, + "⊆": 1611, + "⊕": 1612, + "⊗": 1613, + "⋅": 1614, + "─": 1615, + "│": 1616, + "■": 1617, + "▪": 1618, + "●": 1619, + "★": 1620, + "☆": 1621, + "☉": 1622, + "♠": 1623, + "♣": 1624, + "♥": 1625, + "♦": 1626, + "♭": 1627, + "♯": 1628, + "⟨": 1629, + "⟩": 1630, + "ⱼ": 1631, + "⺩": 1632, + "⺼": 1633, + "⽥": 1634, + "、": 1635, + "。": 1636, + "〈": 1637, + "〉": 1638, + "《": 1639, + "》": 1640, + "「": 1641, + "」": 1642, + "『": 1643, + "』": 1644, + "〜": 1645, + "あ": 1646, + "い": 1647, + "う": 1648, + "え": 1649, + "お": 1650, + "か": 1651, + "き": 1652, + "く": 1653, + "け": 1654, + "こ": 1655, + "さ": 1656, + "し": 1657, + "す": 1658, + "せ": 1659, + "そ": 1660, + "た": 1661, + "ち": 1662, + "っ": 1663, + "つ": 1664, + "て": 1665, + "と": 1666, + "な": 1667, + "に": 1668, + "ぬ": 1669, + "ね": 1670, + "の": 1671, + "は": 1672, + "ひ": 1673, + "ふ": 1674, + "へ": 1675, + "ほ": 1676, + "ま": 1677, + "み": 1678, + "む": 1679, + "め": 1680, + "も": 1681, + "や": 1682, + "ゆ": 1683, + "よ": 1684, + "ら": 1685, + "り": 1686, + "る": 1687, + "れ": 1688, + "ろ": 1689, + "を": 1690, + "ん": 1691, + "ァ": 1692, + "ア": 1693, + "ィ": 1694, + "イ": 1695, + "ウ": 1696, + "ェ": 1697, + "エ": 1698, + "オ": 1699, + "カ": 1700, + "キ": 1701, + "ク": 1702, + "ケ": 1703, + "コ": 1704, + "サ": 1705, + "シ": 1706, + "ス": 1707, + "セ": 1708, + "タ": 1709, + "チ": 1710, + "ッ": 1711, + "ツ": 1712, + "テ": 1713, + "ト": 1714, + "ナ": 1715, + "ニ": 1716, + "ノ": 1717, + "ハ": 1718, + "ヒ": 1719, + "フ": 1720, + "ヘ": 1721, + "ホ": 1722, + "マ": 1723, + "ミ": 1724, + "ム": 1725, + "メ": 1726, + "モ": 1727, + "ャ": 1728, + "ュ": 1729, + "ョ": 1730, + "ラ": 1731, + "リ": 1732, + "ル": 1733, + "レ": 1734, + "ロ": 1735, + "ワ": 1736, + "ン": 1737, + "・": 1738, + "ー": 1739, + "一": 1740, + "三": 1741, + "上": 1742, + "下": 1743, + "不": 1744, + "世": 1745, + "中": 1746, + "主": 1747, + "久": 1748, + "之": 1749, + "也": 1750, + "事": 1751, + "二": 1752, + "五": 1753, + "井": 1754, + "京": 1755, + "人": 1756, + "亻": 1757, + "仁": 1758, + "介": 1759, + "代": 1760, + "仮": 1761, + "伊": 1762, + "会": 1763, + "佐": 1764, + "侍": 1765, + "保": 1766, + "信": 1767, + "健": 1768, + "元": 1769, + "光": 1770, + "八": 1771, + "公": 1772, + "内": 1773, + "出": 1774, + "分": 1775, + "前": 1776, + "劉": 1777, + "力": 1778, + "加": 1779, + "勝": 1780, + "北": 1781, + "区": 1782, + "十": 1783, + "千": 1784, + "南": 1785, + "博": 1786, + "原": 1787, + "口": 1788, + "古": 1789, + "史": 1790, + "司": 1791, + "合": 1792, + "吉": 1793, + "同": 1794, + "名": 1795, + "和": 1796, + "囗": 1797, + "四": 1798, + "国": 1799, + "國": 1800, + "土": 1801, + "地": 1802, + "坂": 1803, + "城": 1804, + "堂": 1805, + "場": 1806, + "士": 1807, + "夏": 1808, + "外": 1809, + "大": 1810, + "天": 1811, + "太": 1812, + "夫": 1813, + "奈": 1814, + "女": 1815, + "子": 1816, + "学": 1817, + "宀": 1818, + "宇": 1819, + "安": 1820, + "宗": 1821, + "定": 1822, + "宣": 1823, + "宮": 1824, + "家": 1825, + "宿": 1826, + "寺": 1827, + "將": 1828, + "小": 1829, + "尚": 1830, + "山": 1831, + "岡": 1832, + "島": 1833, + "崎": 1834, + "川": 1835, + "州": 1836, + "巿": 1837, + "帝": 1838, + "平": 1839, + "年": 1840, + "幸": 1841, + "广": 1842, + "弘": 1843, + "張": 1844, + "彳": 1845, + "後": 1846, + "御": 1847, + "德": 1848, + "心": 1849, + "忄": 1850, + "志": 1851, + "忠": 1852, + "愛": 1853, + "成": 1854, + "我": 1855, + "戦": 1856, + "戸": 1857, + "手": 1858, + "扌": 1859, + "政": 1860, + "文": 1861, + "新": 1862, + "方": 1863, + "日": 1864, + "明": 1865, + "星": 1866, + "春": 1867, + "昭": 1868, + "智": 1869, + "曲": 1870, + "書": 1871, + "月": 1872, + "有": 1873, + "朝": 1874, + "木": 1875, + "本": 1876, + "李": 1877, + "村": 1878, + "東": 1879, + "松": 1880, + "林": 1881, + "森": 1882, + "楊": 1883, + "樹": 1884, + "橋": 1885, + "歌": 1886, + "止": 1887, + "正": 1888, + "武": 1889, + "比": 1890, + "氏": 1891, + "民": 1892, + "水": 1893, + "氵": 1894, + "氷": 1895, + "永": 1896, + "江": 1897, + "沢": 1898, + "河": 1899, + "治": 1900, + "法": 1901, + "海": 1902, + "清": 1903, + "漢": 1904, + "瀬": 1905, + "火": 1906, + "版": 1907, + "犬": 1908, + "王": 1909, + "生": 1910, + "田": 1911, + "男": 1912, + "疒": 1913, + "発": 1914, + "白": 1915, + "的": 1916, + "皇": 1917, + "目": 1918, + "相": 1919, + "省": 1920, + "真": 1921, + "石": 1922, + "示": 1923, + "社": 1924, + "神": 1925, + "福": 1926, + "禾": 1927, + "秀": 1928, + "秋": 1929, + "空": 1930, + "立": 1931, + "章": 1932, + "竹": 1933, + "糹": 1934, + "美": 1935, + "義": 1936, + "耳": 1937, + "良": 1938, + "艹": 1939, + "花": 1940, + "英": 1941, + "華": 1942, + "葉": 1943, + "藤": 1944, + "行": 1945, + "街": 1946, + "西": 1947, + "見": 1948, + "訁": 1949, + "語": 1950, + "谷": 1951, + "貝": 1952, + "貴": 1953, + "車": 1954, + "軍": 1955, + "辶": 1956, + "道": 1957, + "郎": 1958, + "郡": 1959, + "部": 1960, + "都": 1961, + "里": 1962, + "野": 1963, + "金": 1964, + "鈴": 1965, + "镇": 1966, + "長": 1967, + "門": 1968, + "間": 1969, + "阝": 1970, + "阿": 1971, + "陳": 1972, + "陽": 1973, + "雄": 1974, + "青": 1975, + "面": 1976, + "風": 1977, + "食": 1978, + "香": 1979, + "馬": 1980, + "高": 1981, + "龍": 1982, + "龸": 1983, + "fi": 1984, + "fl": 1985, + "!": 1986, + "(": 1987, + ")": 1988, + ",": 1989, + "-": 1990, + ".": 1991, + "/": 1992, + ":": 1993, + "?": 1994, + "~": 1995, + "the": 1996, + "of": 1997, + "and": 1998, + "in": 1999, + "to": 2000, + "was": 2001, + "he": 2002, + "is": 2003, + "as": 2004, + "for": 2005, + "on": 2006, + "with": 2007, + "that": 2008, + "it": 2009, + "his": 2010, + "by": 2011, + "at": 2012, + "from": 2013, + "her": 2014, + "##s": 2015, + "she": 2016, + "you": 2017, + "had": 2018, + "an": 2019, + "were": 2020, + "but": 2021, + "be": 2022, + "this": 2023, + "are": 2024, + "not": 2025, + "my": 2026, + "they": 2027, + "one": 2028, + "which": 2029, + "or": 2030, + "have": 2031, + "him": 2032, + "me": 2033, + "first": 2034, + "all": 2035, + "also": 2036, + "their": 2037, + "has": 2038, + "up": 2039, + "who": 2040, + "out": 2041, + "been": 2042, + "when": 2043, + "after": 2044, + "there": 2045, + "into": 2046, + "new": 2047, + "two": 2048, + "its": 2049, + "##a": 2050, + "time": 2051, + "would": 2052, + "no": 2053, + "what": 2054, + "about": 2055, + "said": 2056, + "we": 2057, + "over": 2058, + "then": 2059, + "other": 2060, + "so": 2061, + "more": 2062, + "##e": 2063, + "can": 2064, + "if": 2065, + "like": 2066, + "back": 2067, + "them": 2068, + "only": 2069, + "some": 2070, + "could": 2071, + "##i": 2072, + "where": 2073, + "just": 2074, + "##ing": 2075, + "during": 2076, + "before": 2077, + "##n": 2078, + "do": 2079, + "##o": 2080, + "made": 2081, + "school": 2082, + "through": 2083, + "than": 2084, + "now": 2085, + "years": 2086, + "most": 2087, + "world": 2088, + "may": 2089, + "between": 2090, + "down": 2091, + "well": 2092, + "three": 2093, + "##d": 2094, + "year": 2095, + "while": 2096, + "will": 2097, + "##ed": 2098, + "##r": 2099, + "##y": 2100, + "later": 2101, + "##t": 2102, + "city": 2103, + "under": 2104, + "around": 2105, + "did": 2106, + "such": 2107, + "being": 2108, + "used": 2109, + "state": 2110, + "people": 2111, + "part": 2112, + "know": 2113, + "against": 2114, + "your": 2115, + "many": 2116, + "second": 2117, + "university": 2118, + "both": 2119, + "national": 2120, + "##er": 2121, + "these": 2122, + "don": 2123, + "known": 2124, + "off": 2125, + "way": 2126, + "until": 2127, + "re": 2128, + "how": 2129, + "even": 2130, + "get": 2131, + "head": 2132, + "...": 2133, + "didn": 2134, + "##ly": 2135, + "team": 2136, + "american": 2137, + "because": 2138, + "de": 2139, + "##l": 2140, + "born": 2141, + "united": 2142, + "film": 2143, + "since": 2144, + "still": 2145, + "long": 2146, + "work": 2147, + "south": 2148, + "us": 2149, + "became": 2150, + "any": 2151, + "high": 2152, + "again": 2153, + "day": 2154, + "family": 2155, + "see": 2156, + "right": 2157, + "man": 2158, + "eyes": 2159, + "house": 2160, + "season": 2161, + "war": 2162, + "states": 2163, + "including": 2164, + "took": 2165, + "life": 2166, + "north": 2167, + "same": 2168, + "each": 2169, + "called": 2170, + "name": 2171, + "much": 2172, + "place": 2173, + "however": 2174, + "go": 2175, + "four": 2176, + "group": 2177, + "another": 2178, + "found": 2179, + "won": 2180, + "area": 2181, + "here": 2182, + "going": 2183, + "10": 2184, + "away": 2185, + "series": 2186, + "left": 2187, + "home": 2188, + "music": 2189, + "best": 2190, + "make": 2191, + "hand": 2192, + "number": 2193, + "company": 2194, + "several": 2195, + "never": 2196, + "last": 2197, + "john": 2198, + "000": 2199, + "very": 2200, + "album": 2201, + "take": 2202, + "end": 2203, + "good": 2204, + "too": 2205, + "following": 2206, + "released": 2207, + "game": 2208, + "played": 2209, + "little": 2210, + "began": 2211, + "district": 2212, + "##m": 2213, + "old": 2214, + "want": 2215, + "those": 2216, + "side": 2217, + "held": 2218, + "own": 2219, + "early": 2220, + "county": 2221, + "ll": 2222, + "league": 2223, + "use": 2224, + "west": 2225, + "##u": 2226, + "face": 2227, + "think": 2228, + "##es": 2229, + "2010": 2230, + "government": 2231, + "##h": 2232, + "march": 2233, + "came": 2234, + "small": 2235, + "general": 2236, + "town": 2237, + "june": 2238, + "##on": 2239, + "line": 2240, + "based": 2241, + "something": 2242, + "##k": 2243, + "september": 2244, + "thought": 2245, + "looked": 2246, + "along": 2247, + "international": 2248, + "2011": 2249, + "air": 2250, + "july": 2251, + "club": 2252, + "went": 2253, + "january": 2254, + "october": 2255, + "our": 2256, + "august": 2257, + "april": 2258, + "york": 2259, + "12": 2260, + "few": 2261, + "2012": 2262, + "2008": 2263, + "east": 2264, + "show": 2265, + "member": 2266, + "college": 2267, + "2009": 2268, + "father": 2269, + "public": 2270, + "##us": 2271, + "come": 2272, + "men": 2273, + "five": 2274, + "set": 2275, + "station": 2276, + "church": 2277, + "##c": 2278, + "next": 2279, + "former": 2280, + "november": 2281, + "room": 2282, + "party": 2283, + "located": 2284, + "december": 2285, + "2013": 2286, + "age": 2287, + "got": 2288, + "2007": 2289, + "##g": 2290, + "system": 2291, + "let": 2292, + "love": 2293, + "2006": 2294, + "though": 2295, + "every": 2296, + "2014": 2297, + "look": 2298, + "song": 2299, + "water": 2300, + "century": 2301, + "without": 2302, + "body": 2303, + "black": 2304, + "night": 2305, + "within": 2306, + "great": 2307, + "women": 2308, + "single": 2309, + "ve": 2310, + "building": 2311, + "large": 2312, + "population": 2313, + "river": 2314, + "named": 2315, + "band": 2316, + "white": 2317, + "started": 2318, + "##an": 2319, + "once": 2320, + "15": 2321, + "20": 2322, + "should": 2323, + "18": 2324, + "2015": 2325, + "service": 2326, + "top": 2327, + "built": 2328, + "british": 2329, + "open": 2330, + "death": 2331, + "king": 2332, + "moved": 2333, + "local": 2334, + "times": 2335, + "children": 2336, + "february": 2337, + "book": 2338, + "why": 2339, + "11": 2340, + "door": 2341, + "need": 2342, + "president": 2343, + "order": 2344, + "final": 2345, + "road": 2346, + "wasn": 2347, + "although": 2348, + "due": 2349, + "major": 2350, + "died": 2351, + "village": 2352, + "third": 2353, + "knew": 2354, + "2016": 2355, + "asked": 2356, + "turned": 2357, + "st": 2358, + "wanted": 2359, + "say": 2360, + "##p": 2361, + "together": 2362, + "received": 2363, + "main": 2364, + "son": 2365, + "served": 2366, + "different": 2367, + "##en": 2368, + "behind": 2369, + "himself": 2370, + "felt": 2371, + "members": 2372, + "power": 2373, + "football": 2374, + "law": 2375, + "voice": 2376, + "play": 2377, + "##in": 2378, + "near": 2379, + "park": 2380, + "history": 2381, + "30": 2382, + "having": 2383, + "2005": 2384, + "16": 2385, + "##man": 2386, + "saw": 2387, + "mother": 2388, + "##al": 2389, + "army": 2390, + "point": 2391, + "front": 2392, + "help": 2393, + "english": 2394, + "street": 2395, + "art": 2396, + "late": 2397, + "hands": 2398, + "games": 2399, + "award": 2400, + "##ia": 2401, + "young": 2402, + "14": 2403, + "put": 2404, + "published": 2405, + "country": 2406, + "division": 2407, + "across": 2408, + "told": 2409, + "13": 2410, + "often": 2411, + "ever": 2412, + "french": 2413, + "london": 2414, + "center": 2415, + "six": 2416, + "red": 2417, + "2017": 2418, + "led": 2419, + "days": 2420, + "include": 2421, + "light": 2422, + "25": 2423, + "find": 2424, + "tell": 2425, + "among": 2426, + "species": 2427, + "really": 2428, + "according": 2429, + "central": 2430, + "half": 2431, + "2004": 2432, + "form": 2433, + "original": 2434, + "gave": 2435, + "office": 2436, + "making": 2437, + "enough": 2438, + "lost": 2439, + "full": 2440, + "opened": 2441, + "must": 2442, + "included": 2443, + "live": 2444, + "given": 2445, + "german": 2446, + "player": 2447, + "run": 2448, + "business": 2449, + "woman": 2450, + "community": 2451, + "cup": 2452, + "might": 2453, + "million": 2454, + "land": 2455, + "2000": 2456, + "court": 2457, + "development": 2458, + "17": 2459, + "short": 2460, + "round": 2461, + "ii": 2462, + "km": 2463, + "seen": 2464, + "class": 2465, + "story": 2466, + "always": 2467, + "become": 2468, + "sure": 2469, + "research": 2470, + "almost": 2471, + "director": 2472, + "council": 2473, + "la": 2474, + "##2": 2475, + "career": 2476, + "things": 2477, + "using": 2478, + "island": 2479, + "##z": 2480, + "couldn": 2481, + "car": 2482, + "##is": 2483, + "24": 2484, + "close": 2485, + "force": 2486, + "##1": 2487, + "better": 2488, + "free": 2489, + "support": 2490, + "control": 2491, + "field": 2492, + "students": 2493, + "2003": 2494, + "education": 2495, + "married": 2496, + "##b": 2497, + "nothing": 2498, + "worked": 2499, + "others": 2500, + "record": 2501, + "big": 2502, + "inside": 2503, + "level": 2504, + "anything": 2505, + "continued": 2506, + "give": 2507, + "james": 2508, + "##3": 2509, + "military": 2510, + "established": 2511, + "non": 2512, + "returned": 2513, + "feel": 2514, + "does": 2515, + "title": 2516, + "written": 2517, + "thing": 2518, + "feet": 2519, + "william": 2520, + "far": 2521, + "co": 2522, + "association": 2523, + "hard": 2524, + "already": 2525, + "2002": 2526, + "##ra": 2527, + "championship": 2528, + "human": 2529, + "western": 2530, + "100": 2531, + "##na": 2532, + "department": 2533, + "hall": 2534, + "role": 2535, + "various": 2536, + "production": 2537, + "21": 2538, + "19": 2539, + "heart": 2540, + "2001": 2541, + "living": 2542, + "fire": 2543, + "version": 2544, + "##ers": 2545, + "##f": 2546, + "television": 2547, + "royal": 2548, + "##4": 2549, + "produced": 2550, + "working": 2551, + "act": 2552, + "case": 2553, + "society": 2554, + "region": 2555, + "present": 2556, + "radio": 2557, + "period": 2558, + "looking": 2559, + "least": 2560, + "total": 2561, + "keep": 2562, + "england": 2563, + "wife": 2564, + "program": 2565, + "per": 2566, + "brother": 2567, + "mind": 2568, + "special": 2569, + "22": 2570, + "##le": 2571, + "am": 2572, + "works": 2573, + "soon": 2574, + "##6": 2575, + "political": 2576, + "george": 2577, + "services": 2578, + "taken": 2579, + "created": 2580, + "##7": 2581, + "further": 2582, + "able": 2583, + "reached": 2584, + "david": 2585, + "union": 2586, + "joined": 2587, + "upon": 2588, + "done": 2589, + "important": 2590, + "social": 2591, + "information": 2592, + "either": 2593, + "##ic": 2594, + "##x": 2595, + "appeared": 2596, + "position": 2597, + "ground": 2598, + "lead": 2599, + "rock": 2600, + "dark": 2601, + "election": 2602, + "23": 2603, + "board": 2604, + "france": 2605, + "hair": 2606, + "course": 2607, + "arms": 2608, + "site": 2609, + "police": 2610, + "girl": 2611, + "instead": 2612, + "real": 2613, + "sound": 2614, + "##v": 2615, + "words": 2616, + "moment": 2617, + "##te": 2618, + "someone": 2619, + "##8": 2620, + "summer": 2621, + "project": 2622, + "announced": 2623, + "san": 2624, + "less": 2625, + "wrote": 2626, + "past": 2627, + "followed": 2628, + "##5": 2629, + "blue": 2630, + "founded": 2631, + "al": 2632, + "finally": 2633, + "india": 2634, + "taking": 2635, + "records": 2636, + "america": 2637, + "##ne": 2638, + "1999": 2639, + "design": 2640, + "considered": 2641, + "northern": 2642, + "god": 2643, + "stop": 2644, + "battle": 2645, + "toward": 2646, + "european": 2647, + "outside": 2648, + "described": 2649, + "track": 2650, + "today": 2651, + "playing": 2652, + "language": 2653, + "28": 2654, + "call": 2655, + "26": 2656, + "heard": 2657, + "professional": 2658, + "low": 2659, + "australia": 2660, + "miles": 2661, + "california": 2662, + "win": 2663, + "yet": 2664, + "green": 2665, + "##ie": 2666, + "trying": 2667, + "blood": 2668, + "##ton": 2669, + "southern": 2670, + "science": 2671, + "maybe": 2672, + "everything": 2673, + "match": 2674, + "square": 2675, + "27": 2676, + "mouth": 2677, + "video": 2678, + "race": 2679, + "recorded": 2680, + "leave": 2681, + "above": 2682, + "##9": 2683, + "daughter": 2684, + "points": 2685, + "space": 2686, + "1998": 2687, + "museum": 2688, + "change": 2689, + "middle": 2690, + "common": 2691, + "##0": 2692, + "move": 2693, + "tv": 2694, + "post": 2695, + "##ta": 2696, + "lake": 2697, + "seven": 2698, + "tried": 2699, + "elected": 2700, + "closed": 2701, + "ten": 2702, + "paul": 2703, + "minister": 2704, + "##th": 2705, + "months": 2706, + "start": 2707, + "chief": 2708, + "return": 2709, + "canada": 2710, + "person": 2711, + "sea": 2712, + "release": 2713, + "similar": 2714, + "modern": 2715, + "brought": 2716, + "rest": 2717, + "hit": 2718, + "formed": 2719, + "mr": 2720, + "##la": 2721, + "1997": 2722, + "floor": 2723, + "event": 2724, + "doing": 2725, + "thomas": 2726, + "1996": 2727, + "robert": 2728, + "care": 2729, + "killed": 2730, + "training": 2731, + "star": 2732, + "week": 2733, + "needed": 2734, + "turn": 2735, + "finished": 2736, + "railway": 2737, + "rather": 2738, + "news": 2739, + "health": 2740, + "sent": 2741, + "example": 2742, + "ran": 2743, + "term": 2744, + "michael": 2745, + "coming": 2746, + "currently": 2747, + "yes": 2748, + "forces": 2749, + "despite": 2750, + "gold": 2751, + "areas": 2752, + "50": 2753, + "stage": 2754, + "fact": 2755, + "29": 2756, + "dead": 2757, + "says": 2758, + "popular": 2759, + "2018": 2760, + "originally": 2761, + "germany": 2762, + "probably": 2763, + "developed": 2764, + "result": 2765, + "pulled": 2766, + "friend": 2767, + "stood": 2768, + "money": 2769, + "running": 2770, + "mi": 2771, + "signed": 2772, + "word": 2773, + "songs": 2774, + "child": 2775, + "eventually": 2776, + "met": 2777, + "tour": 2778, + "average": 2779, + "teams": 2780, + "minutes": 2781, + "festival": 2782, + "current": 2783, + "deep": 2784, + "kind": 2785, + "1995": 2786, + "decided": 2787, + "usually": 2788, + "eastern": 2789, + "seemed": 2790, + "##ness": 2791, + "episode": 2792, + "bed": 2793, + "added": 2794, + "table": 2795, + "indian": 2796, + "private": 2797, + "charles": 2798, + "route": 2799, + "available": 2800, + "idea": 2801, + "throughout": 2802, + "centre": 2803, + "addition": 2804, + "appointed": 2805, + "style": 2806, + "1994": 2807, + "books": 2808, + "eight": 2809, + "construction": 2810, + "press": 2811, + "mean": 2812, + "wall": 2813, + "friends": 2814, + "remained": 2815, + "schools": 2816, + "study": 2817, + "##ch": 2818, + "##um": 2819, + "institute": 2820, + "oh": 2821, + "chinese": 2822, + "sometimes": 2823, + "events": 2824, + "possible": 2825, + "1992": 2826, + "australian": 2827, + "type": 2828, + "brown": 2829, + "forward": 2830, + "talk": 2831, + "process": 2832, + "food": 2833, + "debut": 2834, + "seat": 2835, + "performance": 2836, + "committee": 2837, + "features": 2838, + "character": 2839, + "arts": 2840, + "herself": 2841, + "else": 2842, + "lot": 2843, + "strong": 2844, + "russian": 2845, + "range": 2846, + "hours": 2847, + "peter": 2848, + "arm": 2849, + "##da": 2850, + "morning": 2851, + "dr": 2852, + "sold": 2853, + "##ry": 2854, + "quickly": 2855, + "directed": 2856, + "1993": 2857, + "guitar": 2858, + "china": 2859, + "##w": 2860, + "31": 2861, + "list": 2862, + "##ma": 2863, + "performed": 2864, + "media": 2865, + "uk": 2866, + "players": 2867, + "smile": 2868, + "##rs": 2869, + "myself": 2870, + "40": 2871, + "placed": 2872, + "coach": 2873, + "province": 2874, + "towards": 2875, + "wouldn": 2876, + "leading": 2877, + "whole": 2878, + "boy": 2879, + "official": 2880, + "designed": 2881, + "grand": 2882, + "census": 2883, + "##el": 2884, + "europe": 2885, + "attack": 2886, + "japanese": 2887, + "henry": 2888, + "1991": 2889, + "##re": 2890, + "##os": 2891, + "cross": 2892, + "getting": 2893, + "alone": 2894, + "action": 2895, + "lower": 2896, + "network": 2897, + "wide": 2898, + "washington": 2899, + "japan": 2900, + "1990": 2901, + "hospital": 2902, + "believe": 2903, + "changed": 2904, + "sister": 2905, + "##ar": 2906, + "hold": 2907, + "gone": 2908, + "sir": 2909, + "hadn": 2910, + "ship": 2911, + "##ka": 2912, + "studies": 2913, + "academy": 2914, + "shot": 2915, + "rights": 2916, + "below": 2917, + "base": 2918, + "bad": 2919, + "involved": 2920, + "kept": 2921, + "largest": 2922, + "##ist": 2923, + "bank": 2924, + "future": 2925, + "especially": 2926, + "beginning": 2927, + "mark": 2928, + "movement": 2929, + "section": 2930, + "female": 2931, + "magazine": 2932, + "plan": 2933, + "professor": 2934, + "lord": 2935, + "longer": 2936, + "##ian": 2937, + "sat": 2938, + "walked": 2939, + "hill": 2940, + "actually": 2941, + "civil": 2942, + "energy": 2943, + "model": 2944, + "families": 2945, + "size": 2946, + "thus": 2947, + "aircraft": 2948, + "completed": 2949, + "includes": 2950, + "data": 2951, + "captain": 2952, + "##or": 2953, + "fight": 2954, + "vocals": 2955, + "featured": 2956, + "richard": 2957, + "bridge": 2958, + "fourth": 2959, + "1989": 2960, + "officer": 2961, + "stone": 2962, + "hear": 2963, + "##ism": 2964, + "means": 2965, + "medical": 2966, + "groups": 2967, + "management": 2968, + "self": 2969, + "lips": 2970, + "competition": 2971, + "entire": 2972, + "lived": 2973, + "technology": 2974, + "leaving": 2975, + "federal": 2976, + "tournament": 2977, + "bit": 2978, + "passed": 2979, + "hot": 2980, + "independent": 2981, + "awards": 2982, + "kingdom": 2983, + "mary": 2984, + "spent": 2985, + "fine": 2986, + "doesn": 2987, + "reported": 2988, + "##ling": 2989, + "jack": 2990, + "fall": 2991, + "raised": 2992, + "itself": 2993, + "stay": 2994, + "true": 2995, + "studio": 2996, + "1988": 2997, + "sports": 2998, + "replaced": 2999, + "paris": 3000, + "systems": 3001, + "saint": 3002, + "leader": 3003, + "theatre": 3004, + "whose": 3005, + "market": 3006, + "capital": 3007, + "parents": 3008, + "spanish": 3009, + "canadian": 3010, + "earth": 3011, + "##ity": 3012, + "cut": 3013, + "degree": 3014, + "writing": 3015, + "bay": 3016, + "christian": 3017, + "awarded": 3018, + "natural": 3019, + "higher": 3020, + "bill": 3021, + "##as": 3022, + "coast": 3023, + "provided": 3024, + "previous": 3025, + "senior": 3026, + "ft": 3027, + "valley": 3028, + "organization": 3029, + "stopped": 3030, + "onto": 3031, + "countries": 3032, + "parts": 3033, + "conference": 3034, + "queen": 3035, + "security": 3036, + "interest": 3037, + "saying": 3038, + "allowed": 3039, + "master": 3040, + "earlier": 3041, + "phone": 3042, + "matter": 3043, + "smith": 3044, + "winning": 3045, + "try": 3046, + "happened": 3047, + "moving": 3048, + "campaign": 3049, + "los": 3050, + "##ley": 3051, + "breath": 3052, + "nearly": 3053, + "mid": 3054, + "1987": 3055, + "certain": 3056, + "girls": 3057, + "date": 3058, + "italian": 3059, + "african": 3060, + "standing": 3061, + "fell": 3062, + "artist": 3063, + "##ted": 3064, + "shows": 3065, + "deal": 3066, + "mine": 3067, + "industry": 3068, + "1986": 3069, + "##ng": 3070, + "everyone": 3071, + "republic": 3072, + "provide": 3073, + "collection": 3074, + "library": 3075, + "student": 3076, + "##ville": 3077, + "primary": 3078, + "owned": 3079, + "older": 3080, + "via": 3081, + "heavy": 3082, + "1st": 3083, + "makes": 3084, + "##able": 3085, + "attention": 3086, + "anyone": 3087, + "africa": 3088, + "##ri": 3089, + "stated": 3090, + "length": 3091, + "ended": 3092, + "fingers": 3093, + "command": 3094, + "staff": 3095, + "skin": 3096, + "foreign": 3097, + "opening": 3098, + "governor": 3099, + "okay": 3100, + "medal": 3101, + "kill": 3102, + "sun": 3103, + "cover": 3104, + "job": 3105, + "1985": 3106, + "introduced": 3107, + "chest": 3108, + "hell": 3109, + "feeling": 3110, + "##ies": 3111, + "success": 3112, + "meet": 3113, + "reason": 3114, + "standard": 3115, + "meeting": 3116, + "novel": 3117, + "1984": 3118, + "trade": 3119, + "source": 3120, + "buildings": 3121, + "##land": 3122, + "rose": 3123, + "guy": 3124, + "goal": 3125, + "##ur": 3126, + "chapter": 3127, + "native": 3128, + "husband": 3129, + "previously": 3130, + "unit": 3131, + "limited": 3132, + "entered": 3133, + "weeks": 3134, + "producer": 3135, + "operations": 3136, + "mountain": 3137, + "takes": 3138, + "covered": 3139, + "forced": 3140, + "related": 3141, + "roman": 3142, + "complete": 3143, + "successful": 3144, + "key": 3145, + "texas": 3146, + "cold": 3147, + "##ya": 3148, + "channel": 3149, + "1980": 3150, + "traditional": 3151, + "films": 3152, + "dance": 3153, + "clear": 3154, + "approximately": 3155, + "500": 3156, + "nine": 3157, + "van": 3158, + "prince": 3159, + "question": 3160, + "active": 3161, + "tracks": 3162, + "ireland": 3163, + "regional": 3164, + "silver": 3165, + "author": 3166, + "personal": 3167, + "sense": 3168, + "operation": 3169, + "##ine": 3170, + "economic": 3171, + "1983": 3172, + "holding": 3173, + "twenty": 3174, + "isbn": 3175, + "additional": 3176, + "speed": 3177, + "hour": 3178, + "edition": 3179, + "regular": 3180, + "historic": 3181, + "places": 3182, + "whom": 3183, + "shook": 3184, + "movie": 3185, + "km²": 3186, + "secretary": 3187, + "prior": 3188, + "report": 3189, + "chicago": 3190, + "read": 3191, + "foundation": 3192, + "view": 3193, + "engine": 3194, + "scored": 3195, + "1982": 3196, + "units": 3197, + "ask": 3198, + "airport": 3199, + "property": 3200, + "ready": 3201, + "immediately": 3202, + "lady": 3203, + "month": 3204, + "listed": 3205, + "contract": 3206, + "##de": 3207, + "manager": 3208, + "themselves": 3209, + "lines": 3210, + "##ki": 3211, + "navy": 3212, + "writer": 3213, + "meant": 3214, + "##ts": 3215, + "runs": 3216, + "##ro": 3217, + "practice": 3218, + "championships": 3219, + "singer": 3220, + "glass": 3221, + "commission": 3222, + "required": 3223, + "forest": 3224, + "starting": 3225, + "culture": 3226, + "generally": 3227, + "giving": 3228, + "access": 3229, + "attended": 3230, + "test": 3231, + "couple": 3232, + "stand": 3233, + "catholic": 3234, + "martin": 3235, + "caught": 3236, + "executive": 3237, + "##less": 3238, + "eye": 3239, + "##ey": 3240, + "thinking": 3241, + "chair": 3242, + "quite": 3243, + "shoulder": 3244, + "1979": 3245, + "hope": 3246, + "decision": 3247, + "plays": 3248, + "defeated": 3249, + "municipality": 3250, + "whether": 3251, + "structure": 3252, + "offered": 3253, + "slowly": 3254, + "pain": 3255, + "ice": 3256, + "direction": 3257, + "##ion": 3258, + "paper": 3259, + "mission": 3260, + "1981": 3261, + "mostly": 3262, + "200": 3263, + "noted": 3264, + "individual": 3265, + "managed": 3266, + "nature": 3267, + "lives": 3268, + "plant": 3269, + "##ha": 3270, + "helped": 3271, + "except": 3272, + "studied": 3273, + "computer": 3274, + "figure": 3275, + "relationship": 3276, + "issue": 3277, + "significant": 3278, + "loss": 3279, + "die": 3280, + "smiled": 3281, + "gun": 3282, + "ago": 3283, + "highest": 3284, + "1972": 3285, + "##am": 3286, + "male": 3287, + "bring": 3288, + "goals": 3289, + "mexico": 3290, + "problem": 3291, + "distance": 3292, + "commercial": 3293, + "completely": 3294, + "location": 3295, + "annual": 3296, + "famous": 3297, + "drive": 3298, + "1976": 3299, + "neck": 3300, + "1978": 3301, + "surface": 3302, + "caused": 3303, + "italy": 3304, + "understand": 3305, + "greek": 3306, + "highway": 3307, + "wrong": 3308, + "hotel": 3309, + "comes": 3310, + "appearance": 3311, + "joseph": 3312, + "double": 3313, + "issues": 3314, + "musical": 3315, + "companies": 3316, + "castle": 3317, + "income": 3318, + "review": 3319, + "assembly": 3320, + "bass": 3321, + "initially": 3322, + "parliament": 3323, + "artists": 3324, + "experience": 3325, + "1974": 3326, + "particular": 3327, + "walk": 3328, + "foot": 3329, + "engineering": 3330, + "talking": 3331, + "window": 3332, + "dropped": 3333, + "##ter": 3334, + "miss": 3335, + "baby": 3336, + "boys": 3337, + "break": 3338, + "1975": 3339, + "stars": 3340, + "edge": 3341, + "remember": 3342, + "policy": 3343, + "carried": 3344, + "train": 3345, + "stadium": 3346, + "bar": 3347, + "sex": 3348, + "angeles": 3349, + "evidence": 3350, + "##ge": 3351, + "becoming": 3352, + "assistant": 3353, + "soviet": 3354, + "1977": 3355, + "upper": 3356, + "step": 3357, + "wing": 3358, + "1970": 3359, + "youth": 3360, + "financial": 3361, + "reach": 3362, + "##ll": 3363, + "actor": 3364, + "numerous": 3365, + "##se": 3366, + "##st": 3367, + "nodded": 3368, + "arrived": 3369, + "##ation": 3370, + "minute": 3371, + "##nt": 3372, + "believed": 3373, + "sorry": 3374, + "complex": 3375, + "beautiful": 3376, + "victory": 3377, + "associated": 3378, + "temple": 3379, + "1968": 3380, + "1973": 3381, + "chance": 3382, + "perhaps": 3383, + "metal": 3384, + "##son": 3385, + "1945": 3386, + "bishop": 3387, + "##et": 3388, + "lee": 3389, + "launched": 3390, + "particularly": 3391, + "tree": 3392, + "le": 3393, + "retired": 3394, + "subject": 3395, + "prize": 3396, + "contains": 3397, + "yeah": 3398, + "theory": 3399, + "empire": 3400, + "##ce": 3401, + "suddenly": 3402, + "waiting": 3403, + "trust": 3404, + "recording": 3405, + "##to": 3406, + "happy": 3407, + "terms": 3408, + "camp": 3409, + "champion": 3410, + "1971": 3411, + "religious": 3412, + "pass": 3413, + "zealand": 3414, + "names": 3415, + "2nd": 3416, + "port": 3417, + "ancient": 3418, + "tom": 3419, + "corner": 3420, + "represented": 3421, + "watch": 3422, + "legal": 3423, + "anti": 3424, + "justice": 3425, + "cause": 3426, + "watched": 3427, + "brothers": 3428, + "45": 3429, + "material": 3430, + "changes": 3431, + "simply": 3432, + "response": 3433, + "louis": 3434, + "fast": 3435, + "##ting": 3436, + "answer": 3437, + "60": 3438, + "historical": 3439, + "1969": 3440, + "stories": 3441, + "straight": 3442, + "create": 3443, + "feature": 3444, + "increased": 3445, + "rate": 3446, + "administration": 3447, + "virginia": 3448, + "el": 3449, + "activities": 3450, + "cultural": 3451, + "overall": 3452, + "winner": 3453, + "programs": 3454, + "basketball": 3455, + "legs": 3456, + "guard": 3457, + "beyond": 3458, + "cast": 3459, + "doctor": 3460, + "mm": 3461, + "flight": 3462, + "results": 3463, + "remains": 3464, + "cost": 3465, + "effect": 3466, + "winter": 3467, + "##ble": 3468, + "larger": 3469, + "islands": 3470, + "problems": 3471, + "chairman": 3472, + "grew": 3473, + "commander": 3474, + "isn": 3475, + "1967": 3476, + "pay": 3477, + "failed": 3478, + "selected": 3479, + "hurt": 3480, + "fort": 3481, + "box": 3482, + "regiment": 3483, + "majority": 3484, + "journal": 3485, + "35": 3486, + "edward": 3487, + "plans": 3488, + "##ke": 3489, + "##ni": 3490, + "shown": 3491, + "pretty": 3492, + "irish": 3493, + "characters": 3494, + "directly": 3495, + "scene": 3496, + "likely": 3497, + "operated": 3498, + "allow": 3499, + "spring": 3500, + "##j": 3501, + "junior": 3502, + "matches": 3503, + "looks": 3504, + "mike": 3505, + "houses": 3506, + "fellow": 3507, + "##tion": 3508, + "beach": 3509, + "marriage": 3510, + "##ham": 3511, + "##ive": 3512, + "rules": 3513, + "oil": 3514, + "65": 3515, + "florida": 3516, + "expected": 3517, + "nearby": 3518, + "congress": 3519, + "sam": 3520, + "peace": 3521, + "recent": 3522, + "iii": 3523, + "wait": 3524, + "subsequently": 3525, + "cell": 3526, + "##do": 3527, + "variety": 3528, + "serving": 3529, + "agreed": 3530, + "please": 3531, + "poor": 3532, + "joe": 3533, + "pacific": 3534, + "attempt": 3535, + "wood": 3536, + "democratic": 3537, + "piece": 3538, + "prime": 3539, + "##ca": 3540, + "rural": 3541, + "mile": 3542, + "touch": 3543, + "appears": 3544, + "township": 3545, + "1964": 3546, + "1966": 3547, + "soldiers": 3548, + "##men": 3549, + "##ized": 3550, + "1965": 3551, + "pennsylvania": 3552, + "closer": 3553, + "fighting": 3554, + "claimed": 3555, + "score": 3556, + "jones": 3557, + "physical": 3558, + "editor": 3559, + "##ous": 3560, + "filled": 3561, + "genus": 3562, + "specific": 3563, + "sitting": 3564, + "super": 3565, + "mom": 3566, + "##va": 3567, + "therefore": 3568, + "supported": 3569, + "status": 3570, + "fear": 3571, + "cases": 3572, + "store": 3573, + "meaning": 3574, + "wales": 3575, + "minor": 3576, + "spain": 3577, + "tower": 3578, + "focus": 3579, + "vice": 3580, + "frank": 3581, + "follow": 3582, + "parish": 3583, + "separate": 3584, + "golden": 3585, + "horse": 3586, + "fifth": 3587, + "remaining": 3588, + "branch": 3589, + "32": 3590, + "presented": 3591, + "stared": 3592, + "##id": 3593, + "uses": 3594, + "secret": 3595, + "forms": 3596, + "##co": 3597, + "baseball": 3598, + "exactly": 3599, + "##ck": 3600, + "choice": 3601, + "note": 3602, + "discovered": 3603, + "travel": 3604, + "composed": 3605, + "truth": 3606, + "russia": 3607, + "ball": 3608, + "color": 3609, + "kiss": 3610, + "dad": 3611, + "wind": 3612, + "continue": 3613, + "ring": 3614, + "referred": 3615, + "numbers": 3616, + "digital": 3617, + "greater": 3618, + "##ns": 3619, + "metres": 3620, + "slightly": 3621, + "direct": 3622, + "increase": 3623, + "1960": 3624, + "responsible": 3625, + "crew": 3626, + "rule": 3627, + "trees": 3628, + "troops": 3629, + "##no": 3630, + "broke": 3631, + "goes": 3632, + "individuals": 3633, + "hundred": 3634, + "weight": 3635, + "creek": 3636, + "sleep": 3637, + "memory": 3638, + "defense": 3639, + "provides": 3640, + "ordered": 3641, + "code": 3642, + "value": 3643, + "jewish": 3644, + "windows": 3645, + "1944": 3646, + "safe": 3647, + "judge": 3648, + "whatever": 3649, + "corps": 3650, + "realized": 3651, + "growing": 3652, + "pre": 3653, + "##ga": 3654, + "cities": 3655, + "alexander": 3656, + "gaze": 3657, + "lies": 3658, + "spread": 3659, + "scott": 3660, + "letter": 3661, + "showed": 3662, + "situation": 3663, + "mayor": 3664, + "transport": 3665, + "watching": 3666, + "workers": 3667, + "extended": 3668, + "##li": 3669, + "expression": 3670, + "normal": 3671, + "##ment": 3672, + "chart": 3673, + "multiple": 3674, + "border": 3675, + "##ba": 3676, + "host": 3677, + "##ner": 3678, + "daily": 3679, + "mrs": 3680, + "walls": 3681, + "piano": 3682, + "##ko": 3683, + "heat": 3684, + "cannot": 3685, + "##ate": 3686, + "earned": 3687, + "products": 3688, + "drama": 3689, + "era": 3690, + "authority": 3691, + "seasons": 3692, + "join": 3693, + "grade": 3694, + "##io": 3695, + "sign": 3696, + "difficult": 3697, + "machine": 3698, + "1963": 3699, + "territory": 3700, + "mainly": 3701, + "##wood": 3702, + "stations": 3703, + "squadron": 3704, + "1962": 3705, + "stepped": 3706, + "iron": 3707, + "19th": 3708, + "##led": 3709, + "serve": 3710, + "appear": 3711, + "sky": 3712, + "speak": 3713, + "broken": 3714, + "charge": 3715, + "knowledge": 3716, + "kilometres": 3717, + "removed": 3718, + "ships": 3719, + "article": 3720, + "campus": 3721, + "simple": 3722, + "##ty": 3723, + "pushed": 3724, + "britain": 3725, + "##ve": 3726, + "leaves": 3727, + "recently": 3728, + "cd": 3729, + "soft": 3730, + "boston": 3731, + "latter": 3732, + "easy": 3733, + "acquired": 3734, + "poland": 3735, + "##sa": 3736, + "quality": 3737, + "officers": 3738, + "presence": 3739, + "planned": 3740, + "nations": 3741, + "mass": 3742, + "broadcast": 3743, + "jean": 3744, + "share": 3745, + "image": 3746, + "influence": 3747, + "wild": 3748, + "offer": 3749, + "emperor": 3750, + "electric": 3751, + "reading": 3752, + "headed": 3753, + "ability": 3754, + "promoted": 3755, + "yellow": 3756, + "ministry": 3757, + "1942": 3758, + "throat": 3759, + "smaller": 3760, + "politician": 3761, + "##by": 3762, + "latin": 3763, + "spoke": 3764, + "cars": 3765, + "williams": 3766, + "males": 3767, + "lack": 3768, + "pop": 3769, + "80": 3770, + "##ier": 3771, + "acting": 3772, + "seeing": 3773, + "consists": 3774, + "##ti": 3775, + "estate": 3776, + "1961": 3777, + "pressure": 3778, + "johnson": 3779, + "newspaper": 3780, + "jr": 3781, + "chris": 3782, + "olympics": 3783, + "online": 3784, + "conditions": 3785, + "beat": 3786, + "elements": 3787, + "walking": 3788, + "vote": 3789, + "##field": 3790, + "needs": 3791, + "carolina": 3792, + "text": 3793, + "featuring": 3794, + "global": 3795, + "block": 3796, + "shirt": 3797, + "levels": 3798, + "francisco": 3799, + "purpose": 3800, + "females": 3801, + "et": 3802, + "dutch": 3803, + "duke": 3804, + "ahead": 3805, + "gas": 3806, + "twice": 3807, + "safety": 3808, + "serious": 3809, + "turning": 3810, + "highly": 3811, + "lieutenant": 3812, + "firm": 3813, + "maria": 3814, + "amount": 3815, + "mixed": 3816, + "daniel": 3817, + "proposed": 3818, + "perfect": 3819, + "agreement": 3820, + "affairs": 3821, + "3rd": 3822, + "seconds": 3823, + "contemporary": 3824, + "paid": 3825, + "1943": 3826, + "prison": 3827, + "save": 3828, + "kitchen": 3829, + "label": 3830, + "administrative": 3831, + "intended": 3832, + "constructed": 3833, + "academic": 3834, + "nice": 3835, + "teacher": 3836, + "races": 3837, + "1956": 3838, + "formerly": 3839, + "corporation": 3840, + "ben": 3841, + "nation": 3842, + "issued": 3843, + "shut": 3844, + "1958": 3845, + "drums": 3846, + "housing": 3847, + "victoria": 3848, + "seems": 3849, + "opera": 3850, + "1959": 3851, + "graduated": 3852, + "function": 3853, + "von": 3854, + "mentioned": 3855, + "picked": 3856, + "build": 3857, + "recognized": 3858, + "shortly": 3859, + "protection": 3860, + "picture": 3861, + "notable": 3862, + "exchange": 3863, + "elections": 3864, + "1980s": 3865, + "loved": 3866, + "percent": 3867, + "racing": 3868, + "fish": 3869, + "elizabeth": 3870, + "garden": 3871, + "volume": 3872, + "hockey": 3873, + "1941": 3874, + "beside": 3875, + "settled": 3876, + "##ford": 3877, + "1940": 3878, + "competed": 3879, + "replied": 3880, + "drew": 3881, + "1948": 3882, + "actress": 3883, + "marine": 3884, + "scotland": 3885, + "steel": 3886, + "glanced": 3887, + "farm": 3888, + "steve": 3889, + "1957": 3890, + "risk": 3891, + "tonight": 3892, + "positive": 3893, + "magic": 3894, + "singles": 3895, + "effects": 3896, + "gray": 3897, + "screen": 3898, + "dog": 3899, + "##ja": 3900, + "residents": 3901, + "bus": 3902, + "sides": 3903, + "none": 3904, + "secondary": 3905, + "literature": 3906, + "polish": 3907, + "destroyed": 3908, + "flying": 3909, + "founder": 3910, + "households": 3911, + "1939": 3912, + "lay": 3913, + "reserve": 3914, + "usa": 3915, + "gallery": 3916, + "##ler": 3917, + "1946": 3918, + "industrial": 3919, + "younger": 3920, + "approach": 3921, + "appearances": 3922, + "urban": 3923, + "ones": 3924, + "1950": 3925, + "finish": 3926, + "avenue": 3927, + "powerful": 3928, + "fully": 3929, + "growth": 3930, + "page": 3931, + "honor": 3932, + "jersey": 3933, + "projects": 3934, + "advanced": 3935, + "revealed": 3936, + "basic": 3937, + "90": 3938, + "infantry": 3939, + "pair": 3940, + "equipment": 3941, + "visit": 3942, + "33": 3943, + "evening": 3944, + "search": 3945, + "grant": 3946, + "effort": 3947, + "solo": 3948, + "treatment": 3949, + "buried": 3950, + "republican": 3951, + "primarily": 3952, + "bottom": 3953, + "owner": 3954, + "1970s": 3955, + "israel": 3956, + "gives": 3957, + "jim": 3958, + "dream": 3959, + "bob": 3960, + "remain": 3961, + "spot": 3962, + "70": 3963, + "notes": 3964, + "produce": 3965, + "champions": 3966, + "contact": 3967, + "ed": 3968, + "soul": 3969, + "accepted": 3970, + "ways": 3971, + "del": 3972, + "##ally": 3973, + "losing": 3974, + "split": 3975, + "price": 3976, + "capacity": 3977, + "basis": 3978, + "trial": 3979, + "questions": 3980, + "##ina": 3981, + "1955": 3982, + "20th": 3983, + "guess": 3984, + "officially": 3985, + "memorial": 3986, + "naval": 3987, + "initial": 3988, + "##ization": 3989, + "whispered": 3990, + "median": 3991, + "engineer": 3992, + "##ful": 3993, + "sydney": 3994, + "##go": 3995, + "columbia": 3996, + "strength": 3997, + "300": 3998, + "1952": 3999, + "tears": 4000, + "senate": 4001, + "00": 4002, + "card": 4003, + "asian": 4004, + "agent": 4005, + "1947": 4006, + "software": 4007, + "44": 4008, + "draw": 4009, + "warm": 4010, + "supposed": 4011, + "com": 4012, + "pro": 4013, + "##il": 4014, + "transferred": 4015, + "leaned": 4016, + "##at": 4017, + "candidate": 4018, + "escape": 4019, + "mountains": 4020, + "asia": 4021, + "potential": 4022, + "activity": 4023, + "entertainment": 4024, + "seem": 4025, + "traffic": 4026, + "jackson": 4027, + "murder": 4028, + "36": 4029, + "slow": 4030, + "product": 4031, + "orchestra": 4032, + "haven": 4033, + "agency": 4034, + "bbc": 4035, + "taught": 4036, + "website": 4037, + "comedy": 4038, + "unable": 4039, + "storm": 4040, + "planning": 4041, + "albums": 4042, + "rugby": 4043, + "environment": 4044, + "scientific": 4045, + "grabbed": 4046, + "protect": 4047, + "##hi": 4048, + "boat": 4049, + "typically": 4050, + "1954": 4051, + "1953": 4052, + "damage": 4053, + "principal": 4054, + "divided": 4055, + "dedicated": 4056, + "mount": 4057, + "ohio": 4058, + "##berg": 4059, + "pick": 4060, + "fought": 4061, + "driver": 4062, + "##der": 4063, + "empty": 4064, + "shoulders": 4065, + "sort": 4066, + "thank": 4067, + "berlin": 4068, + "prominent": 4069, + "account": 4070, + "freedom": 4071, + "necessary": 4072, + "efforts": 4073, + "alex": 4074, + "headquarters": 4075, + "follows": 4076, + "alongside": 4077, + "des": 4078, + "simon": 4079, + "andrew": 4080, + "suggested": 4081, + "operating": 4082, + "learning": 4083, + "steps": 4084, + "1949": 4085, + "sweet": 4086, + "technical": 4087, + "begin": 4088, + "easily": 4089, + "34": 4090, + "teeth": 4091, + "speaking": 4092, + "settlement": 4093, + "scale": 4094, + "##sh": 4095, + "renamed": 4096, + "ray": 4097, + "max": 4098, + "enemy": 4099, + "semi": 4100, + "joint": 4101, + "compared": 4102, + "##rd": 4103, + "scottish": 4104, + "leadership": 4105, + "analysis": 4106, + "offers": 4107, + "georgia": 4108, + "pieces": 4109, + "captured": 4110, + "animal": 4111, + "deputy": 4112, + "guest": 4113, + "organized": 4114, + "##lin": 4115, + "tony": 4116, + "combined": 4117, + "method": 4118, + "challenge": 4119, + "1960s": 4120, + "huge": 4121, + "wants": 4122, + "battalion": 4123, + "sons": 4124, + "rise": 4125, + "crime": 4126, + "types": 4127, + "facilities": 4128, + "telling": 4129, + "path": 4130, + "1951": 4131, + "platform": 4132, + "sit": 4133, + "1990s": 4134, + "##lo": 4135, + "tells": 4136, + "assigned": 4137, + "rich": 4138, + "pull": 4139, + "##ot": 4140, + "commonly": 4141, + "alive": 4142, + "##za": 4143, + "letters": 4144, + "concept": 4145, + "conducted": 4146, + "wearing": 4147, + "happen": 4148, + "bought": 4149, + "becomes": 4150, + "holy": 4151, + "gets": 4152, + "ocean": 4153, + "defeat": 4154, + "languages": 4155, + "purchased": 4156, + "coffee": 4157, + "occurred": 4158, + "titled": 4159, + "##q": 4160, + "declared": 4161, + "applied": 4162, + "sciences": 4163, + "concert": 4164, + "sounds": 4165, + "jazz": 4166, + "brain": 4167, + "##me": 4168, + "painting": 4169, + "fleet": 4170, + "tax": 4171, + "nick": 4172, + "##ius": 4173, + "michigan": 4174, + "count": 4175, + "animals": 4176, + "leaders": 4177, + "episodes": 4178, + "##line": 4179, + "content": 4180, + "##den": 4181, + "birth": 4182, + "##it": 4183, + "clubs": 4184, + "64": 4185, + "palace": 4186, + "critical": 4187, + "refused": 4188, + "fair": 4189, + "leg": 4190, + "laughed": 4191, + "returning": 4192, + "surrounding": 4193, + "participated": 4194, + "formation": 4195, + "lifted": 4196, + "pointed": 4197, + "connected": 4198, + "rome": 4199, + "medicine": 4200, + "laid": 4201, + "taylor": 4202, + "santa": 4203, + "powers": 4204, + "adam": 4205, + "tall": 4206, + "shared": 4207, + "focused": 4208, + "knowing": 4209, + "yards": 4210, + "entrance": 4211, + "falls": 4212, + "##wa": 4213, + "calling": 4214, + "##ad": 4215, + "sources": 4216, + "chosen": 4217, + "beneath": 4218, + "resources": 4219, + "yard": 4220, + "##ite": 4221, + "nominated": 4222, + "silence": 4223, + "zone": 4224, + "defined": 4225, + "##que": 4226, + "gained": 4227, + "thirty": 4228, + "38": 4229, + "bodies": 4230, + "moon": 4231, + "##ard": 4232, + "adopted": 4233, + "christmas": 4234, + "widely": 4235, + "register": 4236, + "apart": 4237, + "iran": 4238, + "premier": 4239, + "serves": 4240, + "du": 4241, + "unknown": 4242, + "parties": 4243, + "##les": 4244, + "generation": 4245, + "##ff": 4246, + "continues": 4247, + "quick": 4248, + "fields": 4249, + "brigade": 4250, + "quiet": 4251, + "teaching": 4252, + "clothes": 4253, + "impact": 4254, + "weapons": 4255, + "partner": 4256, + "flat": 4257, + "theater": 4258, + "supreme": 4259, + "1938": 4260, + "37": 4261, + "relations": 4262, + "##tor": 4263, + "plants": 4264, + "suffered": 4265, + "1936": 4266, + "wilson": 4267, + "kids": 4268, + "begins": 4269, + "##age": 4270, + "1918": 4271, + "seats": 4272, + "armed": 4273, + "internet": 4274, + "models": 4275, + "worth": 4276, + "laws": 4277, + "400": 4278, + "communities": 4279, + "classes": 4280, + "background": 4281, + "knows": 4282, + "thanks": 4283, + "quarter": 4284, + "reaching": 4285, + "humans": 4286, + "carry": 4287, + "killing": 4288, + "format": 4289, + "kong": 4290, + "hong": 4291, + "setting": 4292, + "75": 4293, + "architecture": 4294, + "disease": 4295, + "railroad": 4296, + "inc": 4297, + "possibly": 4298, + "wish": 4299, + "arthur": 4300, + "thoughts": 4301, + "harry": 4302, + "doors": 4303, + "density": 4304, + "##di": 4305, + "crowd": 4306, + "illinois": 4307, + "stomach": 4308, + "tone": 4309, + "unique": 4310, + "reports": 4311, + "anyway": 4312, + "##ir": 4313, + "liberal": 4314, + "der": 4315, + "vehicle": 4316, + "thick": 4317, + "dry": 4318, + "drug": 4319, + "faced": 4320, + "largely": 4321, + "facility": 4322, + "theme": 4323, + "holds": 4324, + "creation": 4325, + "strange": 4326, + "colonel": 4327, + "##mi": 4328, + "revolution": 4329, + "bell": 4330, + "politics": 4331, + "turns": 4332, + "silent": 4333, + "rail": 4334, + "relief": 4335, + "independence": 4336, + "combat": 4337, + "shape": 4338, + "write": 4339, + "determined": 4340, + "sales": 4341, + "learned": 4342, + "4th": 4343, + "finger": 4344, + "oxford": 4345, + "providing": 4346, + "1937": 4347, + "heritage": 4348, + "fiction": 4349, + "situated": 4350, + "designated": 4351, + "allowing": 4352, + "distribution": 4353, + "hosted": 4354, + "##est": 4355, + "sight": 4356, + "interview": 4357, + "estimated": 4358, + "reduced": 4359, + "##ria": 4360, + "toronto": 4361, + "footballer": 4362, + "keeping": 4363, + "guys": 4364, + "damn": 4365, + "claim": 4366, + "motion": 4367, + "sport": 4368, + "sixth": 4369, + "stayed": 4370, + "##ze": 4371, + "en": 4372, + "rear": 4373, + "receive": 4374, + "handed": 4375, + "twelve": 4376, + "dress": 4377, + "audience": 4378, + "granted": 4379, + "brazil": 4380, + "##well": 4381, + "spirit": 4382, + "##ated": 4383, + "noticed": 4384, + "etc": 4385, + "olympic": 4386, + "representative": 4387, + "eric": 4388, + "tight": 4389, + "trouble": 4390, + "reviews": 4391, + "drink": 4392, + "vampire": 4393, + "missing": 4394, + "roles": 4395, + "ranked": 4396, + "newly": 4397, + "household": 4398, + "finals": 4399, + "wave": 4400, + "critics": 4401, + "##ee": 4402, + "phase": 4403, + "massachusetts": 4404, + "pilot": 4405, + "unlike": 4406, + "philadelphia": 4407, + "bright": 4408, + "guns": 4409, + "crown": 4410, + "organizations": 4411, + "roof": 4412, + "42": 4413, + "respectively": 4414, + "clearly": 4415, + "tongue": 4416, + "marked": 4417, + "circle": 4418, + "fox": 4419, + "korea": 4420, + "bronze": 4421, + "brian": 4422, + "expanded": 4423, + "sexual": 4424, + "supply": 4425, + "yourself": 4426, + "inspired": 4427, + "labour": 4428, + "fc": 4429, + "##ah": 4430, + "reference": 4431, + "vision": 4432, + "draft": 4433, + "connection": 4434, + "brand": 4435, + "reasons": 4436, + "1935": 4437, + "classic": 4438, + "driving": 4439, + "trip": 4440, + "jesus": 4441, + "cells": 4442, + "entry": 4443, + "1920": 4444, + "neither": 4445, + "trail": 4446, + "claims": 4447, + "atlantic": 4448, + "orders": 4449, + "labor": 4450, + "nose": 4451, + "afraid": 4452, + "identified": 4453, + "intelligence": 4454, + "calls": 4455, + "cancer": 4456, + "attacked": 4457, + "passing": 4458, + "stephen": 4459, + "positions": 4460, + "imperial": 4461, + "grey": 4462, + "jason": 4463, + "39": 4464, + "sunday": 4465, + "48": 4466, + "swedish": 4467, + "avoid": 4468, + "extra": 4469, + "uncle": 4470, + "message": 4471, + "covers": 4472, + "allows": 4473, + "surprise": 4474, + "materials": 4475, + "fame": 4476, + "hunter": 4477, + "##ji": 4478, + "1930": 4479, + "citizens": 4480, + "figures": 4481, + "davis": 4482, + "environmental": 4483, + "confirmed": 4484, + "shit": 4485, + "titles": 4486, + "di": 4487, + "performing": 4488, + "difference": 4489, + "acts": 4490, + "attacks": 4491, + "##ov": 4492, + "existing": 4493, + "votes": 4494, + "opportunity": 4495, + "nor": 4496, + "shop": 4497, + "entirely": 4498, + "trains": 4499, + "opposite": 4500, + "pakistan": 4501, + "##pa": 4502, + "develop": 4503, + "resulted": 4504, + "representatives": 4505, + "actions": 4506, + "reality": 4507, + "pressed": 4508, + "##ish": 4509, + "barely": 4510, + "wine": 4511, + "conversation": 4512, + "faculty": 4513, + "northwest": 4514, + "ends": 4515, + "documentary": 4516, + "nuclear": 4517, + "stock": 4518, + "grace": 4519, + "sets": 4520, + "eat": 4521, + "alternative": 4522, + "##ps": 4523, + "bag": 4524, + "resulting": 4525, + "creating": 4526, + "surprised": 4527, + "cemetery": 4528, + "1919": 4529, + "drop": 4530, + "finding": 4531, + "sarah": 4532, + "cricket": 4533, + "streets": 4534, + "tradition": 4535, + "ride": 4536, + "1933": 4537, + "exhibition": 4538, + "target": 4539, + "ear": 4540, + "explained": 4541, + "rain": 4542, + "composer": 4543, + "injury": 4544, + "apartment": 4545, + "municipal": 4546, + "educational": 4547, + "occupied": 4548, + "netherlands": 4549, + "clean": 4550, + "billion": 4551, + "constitution": 4552, + "learn": 4553, + "1914": 4554, + "maximum": 4555, + "classical": 4556, + "francis": 4557, + "lose": 4558, + "opposition": 4559, + "jose": 4560, + "ontario": 4561, + "bear": 4562, + "core": 4563, + "hills": 4564, + "rolled": 4565, + "ending": 4566, + "drawn": 4567, + "permanent": 4568, + "fun": 4569, + "##tes": 4570, + "##lla": 4571, + "lewis": 4572, + "sites": 4573, + "chamber": 4574, + "ryan": 4575, + "##way": 4576, + "scoring": 4577, + "height": 4578, + "1934": 4579, + "##house": 4580, + "lyrics": 4581, + "staring": 4582, + "55": 4583, + "officials": 4584, + "1917": 4585, + "snow": 4586, + "oldest": 4587, + "##tic": 4588, + "orange": 4589, + "##ger": 4590, + "qualified": 4591, + "interior": 4592, + "apparently": 4593, + "succeeded": 4594, + "thousand": 4595, + "dinner": 4596, + "lights": 4597, + "existence": 4598, + "fans": 4599, + "heavily": 4600, + "41": 4601, + "greatest": 4602, + "conservative": 4603, + "send": 4604, + "bowl": 4605, + "plus": 4606, + "enter": 4607, + "catch": 4608, + "##un": 4609, + "economy": 4610, + "duty": 4611, + "1929": 4612, + "speech": 4613, + "authorities": 4614, + "princess": 4615, + "performances": 4616, + "versions": 4617, + "shall": 4618, + "graduate": 4619, + "pictures": 4620, + "effective": 4621, + "remembered": 4622, + "poetry": 4623, + "desk": 4624, + "crossed": 4625, + "starring": 4626, + "starts": 4627, + "passenger": 4628, + "sharp": 4629, + "##ant": 4630, + "acres": 4631, + "ass": 4632, + "weather": 4633, + "falling": 4634, + "rank": 4635, + "fund": 4636, + "supporting": 4637, + "check": 4638, + "adult": 4639, + "publishing": 4640, + "heads": 4641, + "cm": 4642, + "southeast": 4643, + "lane": 4644, + "##burg": 4645, + "application": 4646, + "bc": 4647, + "##ura": 4648, + "les": 4649, + "condition": 4650, + "transfer": 4651, + "prevent": 4652, + "display": 4653, + "ex": 4654, + "regions": 4655, + "earl": 4656, + "federation": 4657, + "cool": 4658, + "relatively": 4659, + "answered": 4660, + "besides": 4661, + "1928": 4662, + "obtained": 4663, + "portion": 4664, + "##town": 4665, + "mix": 4666, + "##ding": 4667, + "reaction": 4668, + "liked": 4669, + "dean": 4670, + "express": 4671, + "peak": 4672, + "1932": 4673, + "##tte": 4674, + "counter": 4675, + "religion": 4676, + "chain": 4677, + "rare": 4678, + "miller": 4679, + "convention": 4680, + "aid": 4681, + "lie": 4682, + "vehicles": 4683, + "mobile": 4684, + "perform": 4685, + "squad": 4686, + "wonder": 4687, + "lying": 4688, + "crazy": 4689, + "sword": 4690, + "##ping": 4691, + "attempted": 4692, + "centuries": 4693, + "weren": 4694, + "philosophy": 4695, + "category": 4696, + "##ize": 4697, + "anna": 4698, + "interested": 4699, + "47": 4700, + "sweden": 4701, + "wolf": 4702, + "frequently": 4703, + "abandoned": 4704, + "kg": 4705, + "literary": 4706, + "alliance": 4707, + "task": 4708, + "entitled": 4709, + "##ay": 4710, + "threw": 4711, + "promotion": 4712, + "factory": 4713, + "tiny": 4714, + "soccer": 4715, + "visited": 4716, + "matt": 4717, + "fm": 4718, + "achieved": 4719, + "52": 4720, + "defence": 4721, + "internal": 4722, + "persian": 4723, + "43": 4724, + "methods": 4725, + "##ging": 4726, + "arrested": 4727, + "otherwise": 4728, + "cambridge": 4729, + "programming": 4730, + "villages": 4731, + "elementary": 4732, + "districts": 4733, + "rooms": 4734, + "criminal": 4735, + "conflict": 4736, + "worry": 4737, + "trained": 4738, + "1931": 4739, + "attempts": 4740, + "waited": 4741, + "signal": 4742, + "bird": 4743, + "truck": 4744, + "subsequent": 4745, + "programme": 4746, + "##ol": 4747, + "ad": 4748, + "49": 4749, + "communist": 4750, + "details": 4751, + "faith": 4752, + "sector": 4753, + "patrick": 4754, + "carrying": 4755, + "laugh": 4756, + "##ss": 4757, + "controlled": 4758, + "korean": 4759, + "showing": 4760, + "origin": 4761, + "fuel": 4762, + "evil": 4763, + "1927": 4764, + "##ent": 4765, + "brief": 4766, + "identity": 4767, + "darkness": 4768, + "address": 4769, + "pool": 4770, + "missed": 4771, + "publication": 4772, + "web": 4773, + "planet": 4774, + "ian": 4775, + "anne": 4776, + "wings": 4777, + "invited": 4778, + "##tt": 4779, + "briefly": 4780, + "standards": 4781, + "kissed": 4782, + "##be": 4783, + "ideas": 4784, + "climate": 4785, + "causing": 4786, + "walter": 4787, + "worse": 4788, + "albert": 4789, + "articles": 4790, + "winners": 4791, + "desire": 4792, + "aged": 4793, + "northeast": 4794, + "dangerous": 4795, + "gate": 4796, + "doubt": 4797, + "1922": 4798, + "wooden": 4799, + "multi": 4800, + "##ky": 4801, + "poet": 4802, + "rising": 4803, + "funding": 4804, + "46": 4805, + "communications": 4806, + "communication": 4807, + "violence": 4808, + "copies": 4809, + "prepared": 4810, + "ford": 4811, + "investigation": 4812, + "skills": 4813, + "1924": 4814, + "pulling": 4815, + "electronic": 4816, + "##ak": 4817, + "##ial": 4818, + "##han": 4819, + "containing": 4820, + "ultimately": 4821, + "offices": 4822, + "singing": 4823, + "understanding": 4824, + "restaurant": 4825, + "tomorrow": 4826, + "fashion": 4827, + "christ": 4828, + "ward": 4829, + "da": 4830, + "pope": 4831, + "stands": 4832, + "5th": 4833, + "flow": 4834, + "studios": 4835, + "aired": 4836, + "commissioned": 4837, + "contained": 4838, + "exist": 4839, + "fresh": 4840, + "americans": 4841, + "##per": 4842, + "wrestling": 4843, + "approved": 4844, + "kid": 4845, + "employed": 4846, + "respect": 4847, + "suit": 4848, + "1925": 4849, + "angel": 4850, + "asking": 4851, + "increasing": 4852, + "frame": 4853, + "angry": 4854, + "selling": 4855, + "1950s": 4856, + "thin": 4857, + "finds": 4858, + "##nd": 4859, + "temperature": 4860, + "statement": 4861, + "ali": 4862, + "explain": 4863, + "inhabitants": 4864, + "towns": 4865, + "extensive": 4866, + "narrow": 4867, + "51": 4868, + "jane": 4869, + "flowers": 4870, + "images": 4871, + "promise": 4872, + "somewhere": 4873, + "object": 4874, + "fly": 4875, + "closely": 4876, + "##ls": 4877, + "1912": 4878, + "bureau": 4879, + "cape": 4880, + "1926": 4881, + "weekly": 4882, + "presidential": 4883, + "legislative": 4884, + "1921": 4885, + "##ai": 4886, + "##au": 4887, + "launch": 4888, + "founding": 4889, + "##ny": 4890, + "978": 4891, + "##ring": 4892, + "artillery": 4893, + "strike": 4894, + "un": 4895, + "institutions": 4896, + "roll": 4897, + "writers": 4898, + "landing": 4899, + "chose": 4900, + "kevin": 4901, + "anymore": 4902, + "pp": 4903, + "##ut": 4904, + "attorney": 4905, + "fit": 4906, + "dan": 4907, + "billboard": 4908, + "receiving": 4909, + "agricultural": 4910, + "breaking": 4911, + "sought": 4912, + "dave": 4913, + "admitted": 4914, + "lands": 4915, + "mexican": 4916, + "##bury": 4917, + "charlie": 4918, + "specifically": 4919, + "hole": 4920, + "iv": 4921, + "howard": 4922, + "credit": 4923, + "moscow": 4924, + "roads": 4925, + "accident": 4926, + "1923": 4927, + "proved": 4928, + "wear": 4929, + "struck": 4930, + "hey": 4931, + "guards": 4932, + "stuff": 4933, + "slid": 4934, + "expansion": 4935, + "1915": 4936, + "cat": 4937, + "anthony": 4938, + "##kin": 4939, + "melbourne": 4940, + "opposed": 4941, + "sub": 4942, + "southwest": 4943, + "architect": 4944, + "failure": 4945, + "plane": 4946, + "1916": 4947, + "##ron": 4948, + "map": 4949, + "camera": 4950, + "tank": 4951, + "listen": 4952, + "regarding": 4953, + "wet": 4954, + "introduction": 4955, + "metropolitan": 4956, + "link": 4957, + "ep": 4958, + "fighter": 4959, + "inch": 4960, + "grown": 4961, + "gene": 4962, + "anger": 4963, + "fixed": 4964, + "buy": 4965, + "dvd": 4966, + "khan": 4967, + "domestic": 4968, + "worldwide": 4969, + "chapel": 4970, + "mill": 4971, + "functions": 4972, + "examples": 4973, + "##head": 4974, + "developing": 4975, + "1910": 4976, + "turkey": 4977, + "hits": 4978, + "pocket": 4979, + "antonio": 4980, + "papers": 4981, + "grow": 4982, + "unless": 4983, + "circuit": 4984, + "18th": 4985, + "concerned": 4986, + "attached": 4987, + "journalist": 4988, + "selection": 4989, + "journey": 4990, + "converted": 4991, + "provincial": 4992, + "painted": 4993, + "hearing": 4994, + "aren": 4995, + "bands": 4996, + "negative": 4997, + "aside": 4998, + "wondered": 4999, + "knight": 5000, + "lap": 5001, + "survey": 5002, + "ma": 5003, + "##ow": 5004, + "noise": 5005, + "billy": 5006, + "##ium": 5007, + "shooting": 5008, + "guide": 5009, + "bedroom": 5010, + "priest": 5011, + "resistance": 5012, + "motor": 5013, + "homes": 5014, + "sounded": 5015, + "giant": 5016, + "##mer": 5017, + "150": 5018, + "scenes": 5019, + "equal": 5020, + "comic": 5021, + "patients": 5022, + "hidden": 5023, + "solid": 5024, + "actual": 5025, + "bringing": 5026, + "afternoon": 5027, + "touched": 5028, + "funds": 5029, + "wedding": 5030, + "consisted": 5031, + "marie": 5032, + "canal": 5033, + "sr": 5034, + "kim": 5035, + "treaty": 5036, + "turkish": 5037, + "recognition": 5038, + "residence": 5039, + "cathedral": 5040, + "broad": 5041, + "knees": 5042, + "incident": 5043, + "shaped": 5044, + "fired": 5045, + "norwegian": 5046, + "handle": 5047, + "cheek": 5048, + "contest": 5049, + "represent": 5050, + "##pe": 5051, + "representing": 5052, + "beauty": 5053, + "##sen": 5054, + "birds": 5055, + "advantage": 5056, + "emergency": 5057, + "wrapped": 5058, + "drawing": 5059, + "notice": 5060, + "pink": 5061, + "broadcasting": 5062, + "##ong": 5063, + "somehow": 5064, + "bachelor": 5065, + "seventh": 5066, + "collected": 5067, + "registered": 5068, + "establishment": 5069, + "alan": 5070, + "assumed": 5071, + "chemical": 5072, + "personnel": 5073, + "roger": 5074, + "retirement": 5075, + "jeff": 5076, + "portuguese": 5077, + "wore": 5078, + "tied": 5079, + "device": 5080, + "threat": 5081, + "progress": 5082, + "advance": 5083, + "##ised": 5084, + "banks": 5085, + "hired": 5086, + "manchester": 5087, + "nfl": 5088, + "teachers": 5089, + "structures": 5090, + "forever": 5091, + "##bo": 5092, + "tennis": 5093, + "helping": 5094, + "saturday": 5095, + "sale": 5096, + "applications": 5097, + "junction": 5098, + "hip": 5099, + "incorporated": 5100, + "neighborhood": 5101, + "dressed": 5102, + "ceremony": 5103, + "##ds": 5104, + "influenced": 5105, + "hers": 5106, + "visual": 5107, + "stairs": 5108, + "decades": 5109, + "inner": 5110, + "kansas": 5111, + "hung": 5112, + "hoped": 5113, + "gain": 5114, + "scheduled": 5115, + "downtown": 5116, + "engaged": 5117, + "austria": 5118, + "clock": 5119, + "norway": 5120, + "certainly": 5121, + "pale": 5122, + "protected": 5123, + "1913": 5124, + "victor": 5125, + "employees": 5126, + "plate": 5127, + "putting": 5128, + "surrounded": 5129, + "##ists": 5130, + "finishing": 5131, + "blues": 5132, + "tropical": 5133, + "##ries": 5134, + "minnesota": 5135, + "consider": 5136, + "philippines": 5137, + "accept": 5138, + "54": 5139, + "retrieved": 5140, + "1900": 5141, + "concern": 5142, + "anderson": 5143, + "properties": 5144, + "institution": 5145, + "gordon": 5146, + "successfully": 5147, + "vietnam": 5148, + "##dy": 5149, + "backing": 5150, + "outstanding": 5151, + "muslim": 5152, + "crossing": 5153, + "folk": 5154, + "producing": 5155, + "usual": 5156, + "demand": 5157, + "occurs": 5158, + "observed": 5159, + "lawyer": 5160, + "educated": 5161, + "##ana": 5162, + "kelly": 5163, + "string": 5164, + "pleasure": 5165, + "budget": 5166, + "items": 5167, + "quietly": 5168, + "colorado": 5169, + "philip": 5170, + "typical": 5171, + "##worth": 5172, + "derived": 5173, + "600": 5174, + "survived": 5175, + "asks": 5176, + "mental": 5177, + "##ide": 5178, + "56": 5179, + "jake": 5180, + "jews": 5181, + "distinguished": 5182, + "ltd": 5183, + "1911": 5184, + "sri": 5185, + "extremely": 5186, + "53": 5187, + "athletic": 5188, + "loud": 5189, + "thousands": 5190, + "worried": 5191, + "shadow": 5192, + "transportation": 5193, + "horses": 5194, + "weapon": 5195, + "arena": 5196, + "importance": 5197, + "users": 5198, + "tim": 5199, + "objects": 5200, + "contributed": 5201, + "dragon": 5202, + "douglas": 5203, + "aware": 5204, + "senator": 5205, + "johnny": 5206, + "jordan": 5207, + "sisters": 5208, + "engines": 5209, + "flag": 5210, + "investment": 5211, + "samuel": 5212, + "shock": 5213, + "capable": 5214, + "clark": 5215, + "row": 5216, + "wheel": 5217, + "refers": 5218, + "session": 5219, + "familiar": 5220, + "biggest": 5221, + "wins": 5222, + "hate": 5223, + "maintained": 5224, + "drove": 5225, + "hamilton": 5226, + "request": 5227, + "expressed": 5228, + "injured": 5229, + "underground": 5230, + "churches": 5231, + "walker": 5232, + "wars": 5233, + "tunnel": 5234, + "passes": 5235, + "stupid": 5236, + "agriculture": 5237, + "softly": 5238, + "cabinet": 5239, + "regarded": 5240, + "joining": 5241, + "indiana": 5242, + "##ea": 5243, + "##ms": 5244, + "push": 5245, + "dates": 5246, + "spend": 5247, + "behavior": 5248, + "woods": 5249, + "protein": 5250, + "gently": 5251, + "chase": 5252, + "morgan": 5253, + "mention": 5254, + "burning": 5255, + "wake": 5256, + "combination": 5257, + "occur": 5258, + "mirror": 5259, + "leads": 5260, + "jimmy": 5261, + "indeed": 5262, + "impossible": 5263, + "singapore": 5264, + "paintings": 5265, + "covering": 5266, + "##nes": 5267, + "soldier": 5268, + "locations": 5269, + "attendance": 5270, + "sell": 5271, + "historian": 5272, + "wisconsin": 5273, + "invasion": 5274, + "argued": 5275, + "painter": 5276, + "diego": 5277, + "changing": 5278, + "egypt": 5279, + "##don": 5280, + "experienced": 5281, + "inches": 5282, + "##ku": 5283, + "missouri": 5284, + "vol": 5285, + "grounds": 5286, + "spoken": 5287, + "switzerland": 5288, + "##gan": 5289, + "reform": 5290, + "rolling": 5291, + "ha": 5292, + "forget": 5293, + "massive": 5294, + "resigned": 5295, + "burned": 5296, + "allen": 5297, + "tennessee": 5298, + "locked": 5299, + "values": 5300, + "improved": 5301, + "##mo": 5302, + "wounded": 5303, + "universe": 5304, + "sick": 5305, + "dating": 5306, + "facing": 5307, + "pack": 5308, + "purchase": 5309, + "user": 5310, + "##pur": 5311, + "moments": 5312, + "##ul": 5313, + "merged": 5314, + "anniversary": 5315, + "1908": 5316, + "coal": 5317, + "brick": 5318, + "understood": 5319, + "causes": 5320, + "dynasty": 5321, + "queensland": 5322, + "establish": 5323, + "stores": 5324, + "crisis": 5325, + "promote": 5326, + "hoping": 5327, + "views": 5328, + "cards": 5329, + "referee": 5330, + "extension": 5331, + "##si": 5332, + "raise": 5333, + "arizona": 5334, + "improve": 5335, + "colonial": 5336, + "formal": 5337, + "charged": 5338, + "##rt": 5339, + "palm": 5340, + "lucky": 5341, + "hide": 5342, + "rescue": 5343, + "faces": 5344, + "95": 5345, + "feelings": 5346, + "candidates": 5347, + "juan": 5348, + "##ell": 5349, + "goods": 5350, + "6th": 5351, + "courses": 5352, + "weekend": 5353, + "59": 5354, + "luke": 5355, + "cash": 5356, + "fallen": 5357, + "##om": 5358, + "delivered": 5359, + "affected": 5360, + "installed": 5361, + "carefully": 5362, + "tries": 5363, + "swiss": 5364, + "hollywood": 5365, + "costs": 5366, + "lincoln": 5367, + "responsibility": 5368, + "##he": 5369, + "shore": 5370, + "file": 5371, + "proper": 5372, + "normally": 5373, + "maryland": 5374, + "assistance": 5375, + "jump": 5376, + "constant": 5377, + "offering": 5378, + "friendly": 5379, + "waters": 5380, + "persons": 5381, + "realize": 5382, + "contain": 5383, + "trophy": 5384, + "800": 5385, + "partnership": 5386, + "factor": 5387, + "58": 5388, + "musicians": 5389, + "cry": 5390, + "bound": 5391, + "oregon": 5392, + "indicated": 5393, + "hero": 5394, + "houston": 5395, + "medium": 5396, + "##ure": 5397, + "consisting": 5398, + "somewhat": 5399, + "##ara": 5400, + "57": 5401, + "cycle": 5402, + "##che": 5403, + "beer": 5404, + "moore": 5405, + "frederick": 5406, + "gotten": 5407, + "eleven": 5408, + "worst": 5409, + "weak": 5410, + "approached": 5411, + "arranged": 5412, + "chin": 5413, + "loan": 5414, + "universal": 5415, + "bond": 5416, + "fifteen": 5417, + "pattern": 5418, + "disappeared": 5419, + "##ney": 5420, + "translated": 5421, + "##zed": 5422, + "lip": 5423, + "arab": 5424, + "capture": 5425, + "interests": 5426, + "insurance": 5427, + "##chi": 5428, + "shifted": 5429, + "cave": 5430, + "prix": 5431, + "warning": 5432, + "sections": 5433, + "courts": 5434, + "coat": 5435, + "plot": 5436, + "smell": 5437, + "feed": 5438, + "golf": 5439, + "favorite": 5440, + "maintain": 5441, + "knife": 5442, + "vs": 5443, + "voted": 5444, + "degrees": 5445, + "finance": 5446, + "quebec": 5447, + "opinion": 5448, + "translation": 5449, + "manner": 5450, + "ruled": 5451, + "operate": 5452, + "productions": 5453, + "choose": 5454, + "musician": 5455, + "discovery": 5456, + "confused": 5457, + "tired": 5458, + "separated": 5459, + "stream": 5460, + "techniques": 5461, + "committed": 5462, + "attend": 5463, + "ranking": 5464, + "kings": 5465, + "throw": 5466, + "passengers": 5467, + "measure": 5468, + "horror": 5469, + "fan": 5470, + "mining": 5471, + "sand": 5472, + "danger": 5473, + "salt": 5474, + "calm": 5475, + "decade": 5476, + "dam": 5477, + "require": 5478, + "runner": 5479, + "##ik": 5480, + "rush": 5481, + "associate": 5482, + "greece": 5483, + "##ker": 5484, + "rivers": 5485, + "consecutive": 5486, + "matthew": 5487, + "##ski": 5488, + "sighed": 5489, + "sq": 5490, + "documents": 5491, + "steam": 5492, + "edited": 5493, + "closing": 5494, + "tie": 5495, + "accused": 5496, + "1905": 5497, + "##ini": 5498, + "islamic": 5499, + "distributed": 5500, + "directors": 5501, + "organisation": 5502, + "bruce": 5503, + "7th": 5504, + "breathing": 5505, + "mad": 5506, + "lit": 5507, + "arrival": 5508, + "concrete": 5509, + "taste": 5510, + "08": 5511, + "composition": 5512, + "shaking": 5513, + "faster": 5514, + "amateur": 5515, + "adjacent": 5516, + "stating": 5517, + "1906": 5518, + "twin": 5519, + "flew": 5520, + "##ran": 5521, + "tokyo": 5522, + "publications": 5523, + "##tone": 5524, + "obviously": 5525, + "ridge": 5526, + "storage": 5527, + "1907": 5528, + "carl": 5529, + "pages": 5530, + "concluded": 5531, + "desert": 5532, + "driven": 5533, + "universities": 5534, + "ages": 5535, + "terminal": 5536, + "sequence": 5537, + "borough": 5538, + "250": 5539, + "constituency": 5540, + "creative": 5541, + "cousin": 5542, + "economics": 5543, + "dreams": 5544, + "margaret": 5545, + "notably": 5546, + "reduce": 5547, + "montreal": 5548, + "mode": 5549, + "17th": 5550, + "ears": 5551, + "saved": 5552, + "jan": 5553, + "vocal": 5554, + "##ica": 5555, + "1909": 5556, + "andy": 5557, + "##jo": 5558, + "riding": 5559, + "roughly": 5560, + "threatened": 5561, + "##ise": 5562, + "meters": 5563, + "meanwhile": 5564, + "landed": 5565, + "compete": 5566, + "repeated": 5567, + "grass": 5568, + "czech": 5569, + "regularly": 5570, + "charges": 5571, + "tea": 5572, + "sudden": 5573, + "appeal": 5574, + "##ung": 5575, + "solution": 5576, + "describes": 5577, + "pierre": 5578, + "classification": 5579, + "glad": 5580, + "parking": 5581, + "##ning": 5582, + "belt": 5583, + "physics": 5584, + "99": 5585, + "rachel": 5586, + "add": 5587, + "hungarian": 5588, + "participate": 5589, + "expedition": 5590, + "damaged": 5591, + "gift": 5592, + "childhood": 5593, + "85": 5594, + "fifty": 5595, + "##red": 5596, + "mathematics": 5597, + "jumped": 5598, + "letting": 5599, + "defensive": 5600, + "mph": 5601, + "##ux": 5602, + "##gh": 5603, + "testing": 5604, + "##hip": 5605, + "hundreds": 5606, + "shoot": 5607, + "owners": 5608, + "matters": 5609, + "smoke": 5610, + "israeli": 5611, + "kentucky": 5612, + "dancing": 5613, + "mounted": 5614, + "grandfather": 5615, + "emma": 5616, + "designs": 5617, + "profit": 5618, + "argentina": 5619, + "##gs": 5620, + "truly": 5621, + "li": 5622, + "lawrence": 5623, + "cole": 5624, + "begun": 5625, + "detroit": 5626, + "willing": 5627, + "branches": 5628, + "smiling": 5629, + "decide": 5630, + "miami": 5631, + "enjoyed": 5632, + "recordings": 5633, + "##dale": 5634, + "poverty": 5635, + "ethnic": 5636, + "gay": 5637, + "##bi": 5638, + "gary": 5639, + "arabic": 5640, + "09": 5641, + "accompanied": 5642, + "##one": 5643, + "##ons": 5644, + "fishing": 5645, + "determine": 5646, + "residential": 5647, + "acid": 5648, + "##ary": 5649, + "alice": 5650, + "returns": 5651, + "starred": 5652, + "mail": 5653, + "##ang": 5654, + "jonathan": 5655, + "strategy": 5656, + "##ue": 5657, + "net": 5658, + "forty": 5659, + "cook": 5660, + "businesses": 5661, + "equivalent": 5662, + "commonwealth": 5663, + "distinct": 5664, + "ill": 5665, + "##cy": 5666, + "seriously": 5667, + "##ors": 5668, + "##ped": 5669, + "shift": 5670, + "harris": 5671, + "replace": 5672, + "rio": 5673, + "imagine": 5674, + "formula": 5675, + "ensure": 5676, + "##ber": 5677, + "additionally": 5678, + "scheme": 5679, + "conservation": 5680, + "occasionally": 5681, + "purposes": 5682, + "feels": 5683, + "favor": 5684, + "##and": 5685, + "##ore": 5686, + "1930s": 5687, + "contrast": 5688, + "hanging": 5689, + "hunt": 5690, + "movies": 5691, + "1904": 5692, + "instruments": 5693, + "victims": 5694, + "danish": 5695, + "christopher": 5696, + "busy": 5697, + "demon": 5698, + "sugar": 5699, + "earliest": 5700, + "colony": 5701, + "studying": 5702, + "balance": 5703, + "duties": 5704, + "##ks": 5705, + "belgium": 5706, + "slipped": 5707, + "carter": 5708, + "05": 5709, + "visible": 5710, + "stages": 5711, + "iraq": 5712, + "fifa": 5713, + "##im": 5714, + "commune": 5715, + "forming": 5716, + "zero": 5717, + "07": 5718, + "continuing": 5719, + "talked": 5720, + "counties": 5721, + "legend": 5722, + "bathroom": 5723, + "option": 5724, + "tail": 5725, + "clay": 5726, + "daughters": 5727, + "afterwards": 5728, + "severe": 5729, + "jaw": 5730, + "visitors": 5731, + "##ded": 5732, + "devices": 5733, + "aviation": 5734, + "russell": 5735, + "kate": 5736, + "##vi": 5737, + "entering": 5738, + "subjects": 5739, + "##ino": 5740, + "temporary": 5741, + "swimming": 5742, + "forth": 5743, + "smooth": 5744, + "ghost": 5745, + "audio": 5746, + "bush": 5747, + "operates": 5748, + "rocks": 5749, + "movements": 5750, + "signs": 5751, + "eddie": 5752, + "##tz": 5753, + "ann": 5754, + "voices": 5755, + "honorary": 5756, + "06": 5757, + "memories": 5758, + "dallas": 5759, + "pure": 5760, + "measures": 5761, + "racial": 5762, + "promised": 5763, + "66": 5764, + "harvard": 5765, + "ceo": 5766, + "16th": 5767, + "parliamentary": 5768, + "indicate": 5769, + "benefit": 5770, + "flesh": 5771, + "dublin": 5772, + "louisiana": 5773, + "1902": 5774, + "1901": 5775, + "patient": 5776, + "sleeping": 5777, + "1903": 5778, + "membership": 5779, + "coastal": 5780, + "medieval": 5781, + "wanting": 5782, + "element": 5783, + "scholars": 5784, + "rice": 5785, + "62": 5786, + "limit": 5787, + "survive": 5788, + "makeup": 5789, + "rating": 5790, + "definitely": 5791, + "collaboration": 5792, + "obvious": 5793, + "##tan": 5794, + "boss": 5795, + "ms": 5796, + "baron": 5797, + "birthday": 5798, + "linked": 5799, + "soil": 5800, + "diocese": 5801, + "##lan": 5802, + "ncaa": 5803, + "##mann": 5804, + "offensive": 5805, + "shell": 5806, + "shouldn": 5807, + "waist": 5808, + "##tus": 5809, + "plain": 5810, + "ross": 5811, + "organ": 5812, + "resolution": 5813, + "manufacturing": 5814, + "adding": 5815, + "relative": 5816, + "kennedy": 5817, + "98": 5818, + "whilst": 5819, + "moth": 5820, + "marketing": 5821, + "gardens": 5822, + "crash": 5823, + "72": 5824, + "heading": 5825, + "partners": 5826, + "credited": 5827, + "carlos": 5828, + "moves": 5829, + "cable": 5830, + "##zi": 5831, + "marshall": 5832, + "##out": 5833, + "depending": 5834, + "bottle": 5835, + "represents": 5836, + "rejected": 5837, + "responded": 5838, + "existed": 5839, + "04": 5840, + "jobs": 5841, + "denmark": 5842, + "lock": 5843, + "##ating": 5844, + "treated": 5845, + "graham": 5846, + "routes": 5847, + "talent": 5848, + "commissioner": 5849, + "drugs": 5850, + "secure": 5851, + "tests": 5852, + "reign": 5853, + "restored": 5854, + "photography": 5855, + "##gi": 5856, + "contributions": 5857, + "oklahoma": 5858, + "designer": 5859, + "disc": 5860, + "grin": 5861, + "seattle": 5862, + "robin": 5863, + "paused": 5864, + "atlanta": 5865, + "unusual": 5866, + "##gate": 5867, + "praised": 5868, + "las": 5869, + "laughing": 5870, + "satellite": 5871, + "hungary": 5872, + "visiting": 5873, + "##sky": 5874, + "interesting": 5875, + "factors": 5876, + "deck": 5877, + "poems": 5878, + "norman": 5879, + "##water": 5880, + "stuck": 5881, + "speaker": 5882, + "rifle": 5883, + "domain": 5884, + "premiered": 5885, + "##her": 5886, + "dc": 5887, + "comics": 5888, + "actors": 5889, + "01": 5890, + "reputation": 5891, + "eliminated": 5892, + "8th": 5893, + "ceiling": 5894, + "prisoners": 5895, + "script": 5896, + "##nce": 5897, + "leather": 5898, + "austin": 5899, + "mississippi": 5900, + "rapidly": 5901, + "admiral": 5902, + "parallel": 5903, + "charlotte": 5904, + "guilty": 5905, + "tools": 5906, + "gender": 5907, + "divisions": 5908, + "fruit": 5909, + "##bs": 5910, + "laboratory": 5911, + "nelson": 5912, + "fantasy": 5913, + "marry": 5914, + "rapid": 5915, + "aunt": 5916, + "tribe": 5917, + "requirements": 5918, + "aspects": 5919, + "suicide": 5920, + "amongst": 5921, + "adams": 5922, + "bone": 5923, + "ukraine": 5924, + "abc": 5925, + "kick": 5926, + "sees": 5927, + "edinburgh": 5928, + "clothing": 5929, + "column": 5930, + "rough": 5931, + "gods": 5932, + "hunting": 5933, + "broadway": 5934, + "gathered": 5935, + "concerns": 5936, + "##ek": 5937, + "spending": 5938, + "ty": 5939, + "12th": 5940, + "snapped": 5941, + "requires": 5942, + "solar": 5943, + "bones": 5944, + "cavalry": 5945, + "##tta": 5946, + "iowa": 5947, + "drinking": 5948, + "waste": 5949, + "index": 5950, + "franklin": 5951, + "charity": 5952, + "thompson": 5953, + "stewart": 5954, + "tip": 5955, + "flash": 5956, + "landscape": 5957, + "friday": 5958, + "enjoy": 5959, + "singh": 5960, + "poem": 5961, + "listening": 5962, + "##back": 5963, + "eighth": 5964, + "fred": 5965, + "differences": 5966, + "adapted": 5967, + "bomb": 5968, + "ukrainian": 5969, + "surgery": 5970, + "corporate": 5971, + "masters": 5972, + "anywhere": 5973, + "##more": 5974, + "waves": 5975, + "odd": 5976, + "sean": 5977, + "portugal": 5978, + "orleans": 5979, + "dick": 5980, + "debate": 5981, + "kent": 5982, + "eating": 5983, + "puerto": 5984, + "cleared": 5985, + "96": 5986, + "expect": 5987, + "cinema": 5988, + "97": 5989, + "guitarist": 5990, + "blocks": 5991, + "electrical": 5992, + "agree": 5993, + "involving": 5994, + "depth": 5995, + "dying": 5996, + "panel": 5997, + "struggle": 5998, + "##ged": 5999, + "peninsula": 6000, + "adults": 6001, + "novels": 6002, + "emerged": 6003, + "vienna": 6004, + "metro": 6005, + "debuted": 6006, + "shoes": 6007, + "tamil": 6008, + "songwriter": 6009, + "meets": 6010, + "prove": 6011, + "beating": 6012, + "instance": 6013, + "heaven": 6014, + "scared": 6015, + "sending": 6016, + "marks": 6017, + "artistic": 6018, + "passage": 6019, + "superior": 6020, + "03": 6021, + "significantly": 6022, + "shopping": 6023, + "##tive": 6024, + "retained": 6025, + "##izing": 6026, + "malaysia": 6027, + "technique": 6028, + "cheeks": 6029, + "##ola": 6030, + "warren": 6031, + "maintenance": 6032, + "destroy": 6033, + "extreme": 6034, + "allied": 6035, + "120": 6036, + "appearing": 6037, + "##yn": 6038, + "fill": 6039, + "advice": 6040, + "alabama": 6041, + "qualifying": 6042, + "policies": 6043, + "cleveland": 6044, + "hat": 6045, + "battery": 6046, + "smart": 6047, + "authors": 6048, + "10th": 6049, + "soundtrack": 6050, + "acted": 6051, + "dated": 6052, + "lb": 6053, + "glance": 6054, + "equipped": 6055, + "coalition": 6056, + "funny": 6057, + "outer": 6058, + "ambassador": 6059, + "roy": 6060, + "possibility": 6061, + "couples": 6062, + "campbell": 6063, + "dna": 6064, + "loose": 6065, + "ethan": 6066, + "supplies": 6067, + "1898": 6068, + "gonna": 6069, + "88": 6070, + "monster": 6071, + "##res": 6072, + "shake": 6073, + "agents": 6074, + "frequency": 6075, + "springs": 6076, + "dogs": 6077, + "practices": 6078, + "61": 6079, + "gang": 6080, + "plastic": 6081, + "easier": 6082, + "suggests": 6083, + "gulf": 6084, + "blade": 6085, + "exposed": 6086, + "colors": 6087, + "industries": 6088, + "markets": 6089, + "pan": 6090, + "nervous": 6091, + "electoral": 6092, + "charts": 6093, + "legislation": 6094, + "ownership": 6095, + "##idae": 6096, + "mac": 6097, + "appointment": 6098, + "shield": 6099, + "copy": 6100, + "assault": 6101, + "socialist": 6102, + "abbey": 6103, + "monument": 6104, + "license": 6105, + "throne": 6106, + "employment": 6107, + "jay": 6108, + "93": 6109, + "replacement": 6110, + "charter": 6111, + "cloud": 6112, + "powered": 6113, + "suffering": 6114, + "accounts": 6115, + "oak": 6116, + "connecticut": 6117, + "strongly": 6118, + "wright": 6119, + "colour": 6120, + "crystal": 6121, + "13th": 6122, + "context": 6123, + "welsh": 6124, + "networks": 6125, + "voiced": 6126, + "gabriel": 6127, + "jerry": 6128, + "##cing": 6129, + "forehead": 6130, + "mp": 6131, + "##ens": 6132, + "manage": 6133, + "schedule": 6134, + "totally": 6135, + "remix": 6136, + "##ii": 6137, + "forests": 6138, + "occupation": 6139, + "print": 6140, + "nicholas": 6141, + "brazilian": 6142, + "strategic": 6143, + "vampires": 6144, + "engineers": 6145, + "76": 6146, + "roots": 6147, + "seek": 6148, + "correct": 6149, + "instrumental": 6150, + "und": 6151, + "alfred": 6152, + "backed": 6153, + "hop": 6154, + "##des": 6155, + "stanley": 6156, + "robinson": 6157, + "traveled": 6158, + "wayne": 6159, + "welcome": 6160, + "austrian": 6161, + "achieve": 6162, + "67": 6163, + "exit": 6164, + "rates": 6165, + "1899": 6166, + "strip": 6167, + "whereas": 6168, + "##cs": 6169, + "sing": 6170, + "deeply": 6171, + "adventure": 6172, + "bobby": 6173, + "rick": 6174, + "jamie": 6175, + "careful": 6176, + "components": 6177, + "cap": 6178, + "useful": 6179, + "personality": 6180, + "knee": 6181, + "##shi": 6182, + "pushing": 6183, + "hosts": 6184, + "02": 6185, + "protest": 6186, + "ca": 6187, + "ottoman": 6188, + "symphony": 6189, + "##sis": 6190, + "63": 6191, + "boundary": 6192, + "1890": 6193, + "processes": 6194, + "considering": 6195, + "considerable": 6196, + "tons": 6197, + "##work": 6198, + "##ft": 6199, + "##nia": 6200, + "cooper": 6201, + "trading": 6202, + "dear": 6203, + "conduct": 6204, + "91": 6205, + "illegal": 6206, + "apple": 6207, + "revolutionary": 6208, + "holiday": 6209, + "definition": 6210, + "harder": 6211, + "##van": 6212, + "jacob": 6213, + "circumstances": 6214, + "destruction": 6215, + "##lle": 6216, + "popularity": 6217, + "grip": 6218, + "classified": 6219, + "liverpool": 6220, + "donald": 6221, + "baltimore": 6222, + "flows": 6223, + "seeking": 6224, + "honour": 6225, + "approval": 6226, + "92": 6227, + "mechanical": 6228, + "till": 6229, + "happening": 6230, + "statue": 6231, + "critic": 6232, + "increasingly": 6233, + "immediate": 6234, + "describe": 6235, + "commerce": 6236, + "stare": 6237, + "##ster": 6238, + "indonesia": 6239, + "meat": 6240, + "rounds": 6241, + "boats": 6242, + "baker": 6243, + "orthodox": 6244, + "depression": 6245, + "formally": 6246, + "worn": 6247, + "naked": 6248, + "claire": 6249, + "muttered": 6250, + "sentence": 6251, + "11th": 6252, + "emily": 6253, + "document": 6254, + "77": 6255, + "criticism": 6256, + "wished": 6257, + "vessel": 6258, + "spiritual": 6259, + "bent": 6260, + "virgin": 6261, + "parker": 6262, + "minimum": 6263, + "murray": 6264, + "lunch": 6265, + "danny": 6266, + "printed": 6267, + "compilation": 6268, + "keyboards": 6269, + "false": 6270, + "blow": 6271, + "belonged": 6272, + "68": 6273, + "raising": 6274, + "78": 6275, + "cutting": 6276, + "##board": 6277, + "pittsburgh": 6278, + "##up": 6279, + "9th": 6280, + "shadows": 6281, + "81": 6282, + "hated": 6283, + "indigenous": 6284, + "jon": 6285, + "15th": 6286, + "barry": 6287, + "scholar": 6288, + "ah": 6289, + "##zer": 6290, + "oliver": 6291, + "##gy": 6292, + "stick": 6293, + "susan": 6294, + "meetings": 6295, + "attracted": 6296, + "spell": 6297, + "romantic": 6298, + "##ver": 6299, + "ye": 6300, + "1895": 6301, + "photo": 6302, + "demanded": 6303, + "customers": 6304, + "##ac": 6305, + "1896": 6306, + "logan": 6307, + "revival": 6308, + "keys": 6309, + "modified": 6310, + "commanded": 6311, + "jeans": 6312, + "##ious": 6313, + "upset": 6314, + "raw": 6315, + "phil": 6316, + "detective": 6317, + "hiding": 6318, + "resident": 6319, + "vincent": 6320, + "##bly": 6321, + "experiences": 6322, + "diamond": 6323, + "defeating": 6324, + "coverage": 6325, + "lucas": 6326, + "external": 6327, + "parks": 6328, + "franchise": 6329, + "helen": 6330, + "bible": 6331, + "successor": 6332, + "percussion": 6333, + "celebrated": 6334, + "il": 6335, + "lift": 6336, + "profile": 6337, + "clan": 6338, + "romania": 6339, + "##ied": 6340, + "mills": 6341, + "##su": 6342, + "nobody": 6343, + "achievement": 6344, + "shrugged": 6345, + "fault": 6346, + "1897": 6347, + "rhythm": 6348, + "initiative": 6349, + "breakfast": 6350, + "carbon": 6351, + "700": 6352, + "69": 6353, + "lasted": 6354, + "violent": 6355, + "74": 6356, + "wound": 6357, + "ken": 6358, + "killer": 6359, + "gradually": 6360, + "filmed": 6361, + "°c": 6362, + "dollars": 6363, + "processing": 6364, + "94": 6365, + "remove": 6366, + "criticized": 6367, + "guests": 6368, + "sang": 6369, + "chemistry": 6370, + "##vin": 6371, + "legislature": 6372, + "disney": 6373, + "##bridge": 6374, + "uniform": 6375, + "escaped": 6376, + "integrated": 6377, + "proposal": 6378, + "purple": 6379, + "denied": 6380, + "liquid": 6381, + "karl": 6382, + "influential": 6383, + "morris": 6384, + "nights": 6385, + "stones": 6386, + "intense": 6387, + "experimental": 6388, + "twisted": 6389, + "71": 6390, + "84": 6391, + "##ld": 6392, + "pace": 6393, + "nazi": 6394, + "mitchell": 6395, + "ny": 6396, + "blind": 6397, + "reporter": 6398, + "newspapers": 6399, + "14th": 6400, + "centers": 6401, + "burn": 6402, + "basin": 6403, + "forgotten": 6404, + "surviving": 6405, + "filed": 6406, + "collections": 6407, + "monastery": 6408, + "losses": 6409, + "manual": 6410, + "couch": 6411, + "description": 6412, + "appropriate": 6413, + "merely": 6414, + "tag": 6415, + "missions": 6416, + "sebastian": 6417, + "restoration": 6418, + "replacing": 6419, + "triple": 6420, + "73": 6421, + "elder": 6422, + "julia": 6423, + "warriors": 6424, + "benjamin": 6425, + "julian": 6426, + "convinced": 6427, + "stronger": 6428, + "amazing": 6429, + "declined": 6430, + "versus": 6431, + "merchant": 6432, + "happens": 6433, + "output": 6434, + "finland": 6435, + "bare": 6436, + "barbara": 6437, + "absence": 6438, + "ignored": 6439, + "dawn": 6440, + "injuries": 6441, + "##port": 6442, + "producers": 6443, + "##ram": 6444, + "82": 6445, + "luis": 6446, + "##ities": 6447, + "kw": 6448, + "admit": 6449, + "expensive": 6450, + "electricity": 6451, + "nba": 6452, + "exception": 6453, + "symbol": 6454, + "##ving": 6455, + "ladies": 6456, + "shower": 6457, + "sheriff": 6458, + "characteristics": 6459, + "##je": 6460, + "aimed": 6461, + "button": 6462, + "ratio": 6463, + "effectively": 6464, + "summit": 6465, + "angle": 6466, + "jury": 6467, + "bears": 6468, + "foster": 6469, + "vessels": 6470, + "pants": 6471, + "executed": 6472, + "evans": 6473, + "dozen": 6474, + "advertising": 6475, + "kicked": 6476, + "patrol": 6477, + "1889": 6478, + "competitions": 6479, + "lifetime": 6480, + "principles": 6481, + "athletics": 6482, + "##logy": 6483, + "birmingham": 6484, + "sponsored": 6485, + "89": 6486, + "rob": 6487, + "nomination": 6488, + "1893": 6489, + "acoustic": 6490, + "##sm": 6491, + "creature": 6492, + "longest": 6493, + "##tra": 6494, + "credits": 6495, + "harbor": 6496, + "dust": 6497, + "josh": 6498, + "##so": 6499, + "territories": 6500, + "milk": 6501, + "infrastructure": 6502, + "completion": 6503, + "thailand": 6504, + "indians": 6505, + "leon": 6506, + "archbishop": 6507, + "##sy": 6508, + "assist": 6509, + "pitch": 6510, + "blake": 6511, + "arrangement": 6512, + "girlfriend": 6513, + "serbian": 6514, + "operational": 6515, + "hence": 6516, + "sad": 6517, + "scent": 6518, + "fur": 6519, + "dj": 6520, + "sessions": 6521, + "hp": 6522, + "refer": 6523, + "rarely": 6524, + "##ora": 6525, + "exists": 6526, + "1892": 6527, + "##ten": 6528, + "scientists": 6529, + "dirty": 6530, + "penalty": 6531, + "burst": 6532, + "portrait": 6533, + "seed": 6534, + "79": 6535, + "pole": 6536, + "limits": 6537, + "rival": 6538, + "1894": 6539, + "stable": 6540, + "alpha": 6541, + "grave": 6542, + "constitutional": 6543, + "alcohol": 6544, + "arrest": 6545, + "flower": 6546, + "mystery": 6547, + "devil": 6548, + "architectural": 6549, + "relationships": 6550, + "greatly": 6551, + "habitat": 6552, + "##istic": 6553, + "larry": 6554, + "progressive": 6555, + "remote": 6556, + "cotton": 6557, + "##ics": 6558, + "##ok": 6559, + "preserved": 6560, + "reaches": 6561, + "##ming": 6562, + "cited": 6563, + "86": 6564, + "vast": 6565, + "scholarship": 6566, + "decisions": 6567, + "cbs": 6568, + "joy": 6569, + "teach": 6570, + "1885": 6571, + "editions": 6572, + "knocked": 6573, + "eve": 6574, + "searching": 6575, + "partly": 6576, + "participation": 6577, + "gap": 6578, + "animated": 6579, + "fate": 6580, + "excellent": 6581, + "##ett": 6582, + "na": 6583, + "87": 6584, + "alternate": 6585, + "saints": 6586, + "youngest": 6587, + "##ily": 6588, + "climbed": 6589, + "##ita": 6590, + "##tors": 6591, + "suggest": 6592, + "##ct": 6593, + "discussion": 6594, + "staying": 6595, + "choir": 6596, + "lakes": 6597, + "jacket": 6598, + "revenue": 6599, + "nevertheless": 6600, + "peaked": 6601, + "instrument": 6602, + "wondering": 6603, + "annually": 6604, + "managing": 6605, + "neil": 6606, + "1891": 6607, + "signing": 6608, + "terry": 6609, + "##ice": 6610, + "apply": 6611, + "clinical": 6612, + "brooklyn": 6613, + "aim": 6614, + "catherine": 6615, + "fuck": 6616, + "farmers": 6617, + "figured": 6618, + "ninth": 6619, + "pride": 6620, + "hugh": 6621, + "evolution": 6622, + "ordinary": 6623, + "involvement": 6624, + "comfortable": 6625, + "shouted": 6626, + "tech": 6627, + "encouraged": 6628, + "taiwan": 6629, + "representation": 6630, + "sharing": 6631, + "##lia": 6632, + "##em": 6633, + "panic": 6634, + "exact": 6635, + "cargo": 6636, + "competing": 6637, + "fat": 6638, + "cried": 6639, + "83": 6640, + "1920s": 6641, + "occasions": 6642, + "pa": 6643, + "cabin": 6644, + "borders": 6645, + "utah": 6646, + "marcus": 6647, + "##isation": 6648, + "badly": 6649, + "muscles": 6650, + "##ance": 6651, + "victorian": 6652, + "transition": 6653, + "warner": 6654, + "bet": 6655, + "permission": 6656, + "##rin": 6657, + "slave": 6658, + "terrible": 6659, + "similarly": 6660, + "shares": 6661, + "seth": 6662, + "uefa": 6663, + "possession": 6664, + "medals": 6665, + "benefits": 6666, + "colleges": 6667, + "lowered": 6668, + "perfectly": 6669, + "mall": 6670, + "transit": 6671, + "##ye": 6672, + "##kar": 6673, + "publisher": 6674, + "##ened": 6675, + "harrison": 6676, + "deaths": 6677, + "elevation": 6678, + "##ae": 6679, + "asleep": 6680, + "machines": 6681, + "sigh": 6682, + "ash": 6683, + "hardly": 6684, + "argument": 6685, + "occasion": 6686, + "parent": 6687, + "leo": 6688, + "decline": 6689, + "1888": 6690, + "contribution": 6691, + "##ua": 6692, + "concentration": 6693, + "1000": 6694, + "opportunities": 6695, + "hispanic": 6696, + "guardian": 6697, + "extent": 6698, + "emotions": 6699, + "hips": 6700, + "mason": 6701, + "volumes": 6702, + "bloody": 6703, + "controversy": 6704, + "diameter": 6705, + "steady": 6706, + "mistake": 6707, + "phoenix": 6708, + "identify": 6709, + "violin": 6710, + "##sk": 6711, + "departure": 6712, + "richmond": 6713, + "spin": 6714, + "funeral": 6715, + "enemies": 6716, + "1864": 6717, + "gear": 6718, + "literally": 6719, + "connor": 6720, + "random": 6721, + "sergeant": 6722, + "grab": 6723, + "confusion": 6724, + "1865": 6725, + "transmission": 6726, + "informed": 6727, + "op": 6728, + "leaning": 6729, + "sacred": 6730, + "suspended": 6731, + "thinks": 6732, + "gates": 6733, + "portland": 6734, + "luck": 6735, + "agencies": 6736, + "yours": 6737, + "hull": 6738, + "expert": 6739, + "muscle": 6740, + "layer": 6741, + "practical": 6742, + "sculpture": 6743, + "jerusalem": 6744, + "latest": 6745, + "lloyd": 6746, + "statistics": 6747, + "deeper": 6748, + "recommended": 6749, + "warrior": 6750, + "arkansas": 6751, + "mess": 6752, + "supports": 6753, + "greg": 6754, + "eagle": 6755, + "1880": 6756, + "recovered": 6757, + "rated": 6758, + "concerts": 6759, + "rushed": 6760, + "##ano": 6761, + "stops": 6762, + "eggs": 6763, + "files": 6764, + "premiere": 6765, + "keith": 6766, + "##vo": 6767, + "delhi": 6768, + "turner": 6769, + "pit": 6770, + "affair": 6771, + "belief": 6772, + "paint": 6773, + "##zing": 6774, + "mate": 6775, + "##ach": 6776, + "##ev": 6777, + "victim": 6778, + "##ology": 6779, + "withdrew": 6780, + "bonus": 6781, + "styles": 6782, + "fled": 6783, + "##ud": 6784, + "glasgow": 6785, + "technologies": 6786, + "funded": 6787, + "nbc": 6788, + "adaptation": 6789, + "##ata": 6790, + "portrayed": 6791, + "cooperation": 6792, + "supporters": 6793, + "judges": 6794, + "bernard": 6795, + "justin": 6796, + "hallway": 6797, + "ralph": 6798, + "##ick": 6799, + "graduating": 6800, + "controversial": 6801, + "distant": 6802, + "continental": 6803, + "spider": 6804, + "bite": 6805, + "##ho": 6806, + "recognize": 6807, + "intention": 6808, + "mixing": 6809, + "##ese": 6810, + "egyptian": 6811, + "bow": 6812, + "tourism": 6813, + "suppose": 6814, + "claiming": 6815, + "tiger": 6816, + "dominated": 6817, + "participants": 6818, + "vi": 6819, + "##ru": 6820, + "nurse": 6821, + "partially": 6822, + "tape": 6823, + "##rum": 6824, + "psychology": 6825, + "##rn": 6826, + "essential": 6827, + "touring": 6828, + "duo": 6829, + "voting": 6830, + "civilian": 6831, + "emotional": 6832, + "channels": 6833, + "##king": 6834, + "apparent": 6835, + "hebrew": 6836, + "1887": 6837, + "tommy": 6838, + "carrier": 6839, + "intersection": 6840, + "beast": 6841, + "hudson": 6842, + "##gar": 6843, + "##zo": 6844, + "lab": 6845, + "nova": 6846, + "bench": 6847, + "discuss": 6848, + "costa": 6849, + "##ered": 6850, + "detailed": 6851, + "behalf": 6852, + "drivers": 6853, + "unfortunately": 6854, + "obtain": 6855, + "##lis": 6856, + "rocky": 6857, + "##dae": 6858, + "siege": 6859, + "friendship": 6860, + "honey": 6861, + "##rian": 6862, + "1861": 6863, + "amy": 6864, + "hang": 6865, + "posted": 6866, + "governments": 6867, + "collins": 6868, + "respond": 6869, + "wildlife": 6870, + "preferred": 6871, + "operator": 6872, + "##po": 6873, + "laura": 6874, + "pregnant": 6875, + "videos": 6876, + "dennis": 6877, + "suspected": 6878, + "boots": 6879, + "instantly": 6880, + "weird": 6881, + "automatic": 6882, + "businessman": 6883, + "alleged": 6884, + "placing": 6885, + "throwing": 6886, + "ph": 6887, + "mood": 6888, + "1862": 6889, + "perry": 6890, + "venue": 6891, + "jet": 6892, + "remainder": 6893, + "##lli": 6894, + "##ci": 6895, + "passion": 6896, + "biological": 6897, + "boyfriend": 6898, + "1863": 6899, + "dirt": 6900, + "buffalo": 6901, + "ron": 6902, + "segment": 6903, + "fa": 6904, + "abuse": 6905, + "##era": 6906, + "genre": 6907, + "thrown": 6908, + "stroke": 6909, + "colored": 6910, + "stress": 6911, + "exercise": 6912, + "displayed": 6913, + "##gen": 6914, + "struggled": 6915, + "##tti": 6916, + "abroad": 6917, + "dramatic": 6918, + "wonderful": 6919, + "thereafter": 6920, + "madrid": 6921, + "component": 6922, + "widespread": 6923, + "##sed": 6924, + "tale": 6925, + "citizen": 6926, + "todd": 6927, + "monday": 6928, + "1886": 6929, + "vancouver": 6930, + "overseas": 6931, + "forcing": 6932, + "crying": 6933, + "descent": 6934, + "##ris": 6935, + "discussed": 6936, + "substantial": 6937, + "ranks": 6938, + "regime": 6939, + "1870": 6940, + "provinces": 6941, + "switch": 6942, + "drum": 6943, + "zane": 6944, + "ted": 6945, + "tribes": 6946, + "proof": 6947, + "lp": 6948, + "cream": 6949, + "researchers": 6950, + "volunteer": 6951, + "manor": 6952, + "silk": 6953, + "milan": 6954, + "donated": 6955, + "allies": 6956, + "venture": 6957, + "principle": 6958, + "delivery": 6959, + "enterprise": 6960, + "##ves": 6961, + "##ans": 6962, + "bars": 6963, + "traditionally": 6964, + "witch": 6965, + "reminded": 6966, + "copper": 6967, + "##uk": 6968, + "pete": 6969, + "inter": 6970, + "links": 6971, + "colin": 6972, + "grinned": 6973, + "elsewhere": 6974, + "competitive": 6975, + "frequent": 6976, + "##oy": 6977, + "scream": 6978, + "##hu": 6979, + "tension": 6980, + "texts": 6981, + "submarine": 6982, + "finnish": 6983, + "defending": 6984, + "defend": 6985, + "pat": 6986, + "detail": 6987, + "1884": 6988, + "affiliated": 6989, + "stuart": 6990, + "themes": 6991, + "villa": 6992, + "periods": 6993, + "tool": 6994, + "belgian": 6995, + "ruling": 6996, + "crimes": 6997, + "answers": 6998, + "folded": 6999, + "licensed": 7000, + "resort": 7001, + "demolished": 7002, + "hans": 7003, + "lucy": 7004, + "1881": 7005, + "lion": 7006, + "traded": 7007, + "photographs": 7008, + "writes": 7009, + "craig": 7010, + "##fa": 7011, + "trials": 7012, + "generated": 7013, + "beth": 7014, + "noble": 7015, + "debt": 7016, + "percentage": 7017, + "yorkshire": 7018, + "erected": 7019, + "ss": 7020, + "viewed": 7021, + "grades": 7022, + "confidence": 7023, + "ceased": 7024, + "islam": 7025, + "telephone": 7026, + "retail": 7027, + "##ible": 7028, + "chile": 7029, + "m²": 7030, + "roberts": 7031, + "sixteen": 7032, + "##ich": 7033, + "commented": 7034, + "hampshire": 7035, + "innocent": 7036, + "dual": 7037, + "pounds": 7038, + "checked": 7039, + "regulations": 7040, + "afghanistan": 7041, + "sung": 7042, + "rico": 7043, + "liberty": 7044, + "assets": 7045, + "bigger": 7046, + "options": 7047, + "angels": 7048, + "relegated": 7049, + "tribute": 7050, + "wells": 7051, + "attending": 7052, + "leaf": 7053, + "##yan": 7054, + "butler": 7055, + "romanian": 7056, + "forum": 7057, + "monthly": 7058, + "lisa": 7059, + "patterns": 7060, + "gmina": 7061, + "##tory": 7062, + "madison": 7063, + "hurricane": 7064, + "rev": 7065, + "##ians": 7066, + "bristol": 7067, + "##ula": 7068, + "elite": 7069, + "valuable": 7070, + "disaster": 7071, + "democracy": 7072, + "awareness": 7073, + "germans": 7074, + "freyja": 7075, + "##ins": 7076, + "loop": 7077, + "absolutely": 7078, + "paying": 7079, + "populations": 7080, + "maine": 7081, + "sole": 7082, + "prayer": 7083, + "spencer": 7084, + "releases": 7085, + "doorway": 7086, + "bull": 7087, + "##ani": 7088, + "lover": 7089, + "midnight": 7090, + "conclusion": 7091, + "##sson": 7092, + "thirteen": 7093, + "lily": 7094, + "mediterranean": 7095, + "##lt": 7096, + "nhl": 7097, + "proud": 7098, + "sample": 7099, + "##hill": 7100, + "drummer": 7101, + "guinea": 7102, + "##ova": 7103, + "murphy": 7104, + "climb": 7105, + "##ston": 7106, + "instant": 7107, + "attributed": 7108, + "horn": 7109, + "ain": 7110, + "railways": 7111, + "steven": 7112, + "##ao": 7113, + "autumn": 7114, + "ferry": 7115, + "opponent": 7116, + "root": 7117, + "traveling": 7118, + "secured": 7119, + "corridor": 7120, + "stretched": 7121, + "tales": 7122, + "sheet": 7123, + "trinity": 7124, + "cattle": 7125, + "helps": 7126, + "indicates": 7127, + "manhattan": 7128, + "murdered": 7129, + "fitted": 7130, + "1882": 7131, + "gentle": 7132, + "grandmother": 7133, + "mines": 7134, + "shocked": 7135, + "vegas": 7136, + "produces": 7137, + "##light": 7138, + "caribbean": 7139, + "##ou": 7140, + "belong": 7141, + "continuous": 7142, + "desperate": 7143, + "drunk": 7144, + "historically": 7145, + "trio": 7146, + "waved": 7147, + "raf": 7148, + "dealing": 7149, + "nathan": 7150, + "bat": 7151, + "murmured": 7152, + "interrupted": 7153, + "residing": 7154, + "scientist": 7155, + "pioneer": 7156, + "harold": 7157, + "aaron": 7158, + "##net": 7159, + "delta": 7160, + "attempting": 7161, + "minority": 7162, + "mini": 7163, + "believes": 7164, + "chorus": 7165, + "tend": 7166, + "lots": 7167, + "eyed": 7168, + "indoor": 7169, + "load": 7170, + "shots": 7171, + "updated": 7172, + "jail": 7173, + "##llo": 7174, + "concerning": 7175, + "connecting": 7176, + "wealth": 7177, + "##ved": 7178, + "slaves": 7179, + "arrive": 7180, + "rangers": 7181, + "sufficient": 7182, + "rebuilt": 7183, + "##wick": 7184, + "cardinal": 7185, + "flood": 7186, + "muhammad": 7187, + "whenever": 7188, + "relation": 7189, + "runners": 7190, + "moral": 7191, + "repair": 7192, + "viewers": 7193, + "arriving": 7194, + "revenge": 7195, + "punk": 7196, + "assisted": 7197, + "bath": 7198, + "fairly": 7199, + "breathe": 7200, + "lists": 7201, + "innings": 7202, + "illustrated": 7203, + "whisper": 7204, + "nearest": 7205, + "voters": 7206, + "clinton": 7207, + "ties": 7208, + "ultimate": 7209, + "screamed": 7210, + "beijing": 7211, + "lions": 7212, + "andre": 7213, + "fictional": 7214, + "gathering": 7215, + "comfort": 7216, + "radar": 7217, + "suitable": 7218, + "dismissed": 7219, + "hms": 7220, + "ban": 7221, + "pine": 7222, + "wrist": 7223, + "atmosphere": 7224, + "voivodeship": 7225, + "bid": 7226, + "timber": 7227, + "##ned": 7228, + "##nan": 7229, + "giants": 7230, + "##ane": 7231, + "cameron": 7232, + "recovery": 7233, + "uss": 7234, + "identical": 7235, + "categories": 7236, + "switched": 7237, + "serbia": 7238, + "laughter": 7239, + "noah": 7240, + "ensemble": 7241, + "therapy": 7242, + "peoples": 7243, + "touching": 7244, + "##off": 7245, + "locally": 7246, + "pearl": 7247, + "platforms": 7248, + "everywhere": 7249, + "ballet": 7250, + "tables": 7251, + "lanka": 7252, + "herbert": 7253, + "outdoor": 7254, + "toured": 7255, + "derek": 7256, + "1883": 7257, + "spaces": 7258, + "contested": 7259, + "swept": 7260, + "1878": 7261, + "exclusive": 7262, + "slight": 7263, + "connections": 7264, + "##dra": 7265, + "winds": 7266, + "prisoner": 7267, + "collective": 7268, + "bangladesh": 7269, + "tube": 7270, + "publicly": 7271, + "wealthy": 7272, + "thai": 7273, + "##ys": 7274, + "isolated": 7275, + "select": 7276, + "##ric": 7277, + "insisted": 7278, + "pen": 7279, + "fortune": 7280, + "ticket": 7281, + "spotted": 7282, + "reportedly": 7283, + "animation": 7284, + "enforcement": 7285, + "tanks": 7286, + "110": 7287, + "decides": 7288, + "wider": 7289, + "lowest": 7290, + "owen": 7291, + "##time": 7292, + "nod": 7293, + "hitting": 7294, + "##hn": 7295, + "gregory": 7296, + "furthermore": 7297, + "magazines": 7298, + "fighters": 7299, + "solutions": 7300, + "##ery": 7301, + "pointing": 7302, + "requested": 7303, + "peru": 7304, + "reed": 7305, + "chancellor": 7306, + "knights": 7307, + "mask": 7308, + "worker": 7309, + "eldest": 7310, + "flames": 7311, + "reduction": 7312, + "1860": 7313, + "volunteers": 7314, + "##tis": 7315, + "reporting": 7316, + "##hl": 7317, + "wire": 7318, + "advisory": 7319, + "endemic": 7320, + "origins": 7321, + "settlers": 7322, + "pursue": 7323, + "knock": 7324, + "consumer": 7325, + "1876": 7326, + "eu": 7327, + "compound": 7328, + "creatures": 7329, + "mansion": 7330, + "sentenced": 7331, + "ivan": 7332, + "deployed": 7333, + "guitars": 7334, + "frowned": 7335, + "involves": 7336, + "mechanism": 7337, + "kilometers": 7338, + "perspective": 7339, + "shops": 7340, + "maps": 7341, + "terminus": 7342, + "duncan": 7343, + "alien": 7344, + "fist": 7345, + "bridges": 7346, + "##pers": 7347, + "heroes": 7348, + "fed": 7349, + "derby": 7350, + "swallowed": 7351, + "##ros": 7352, + "patent": 7353, + "sara": 7354, + "illness": 7355, + "characterized": 7356, + "adventures": 7357, + "slide": 7358, + "hawaii": 7359, + "jurisdiction": 7360, + "##op": 7361, + "organised": 7362, + "##side": 7363, + "adelaide": 7364, + "walks": 7365, + "biology": 7366, + "se": 7367, + "##ties": 7368, + "rogers": 7369, + "swing": 7370, + "tightly": 7371, + "boundaries": 7372, + "##rie": 7373, + "prepare": 7374, + "implementation": 7375, + "stolen": 7376, + "##sha": 7377, + "certified": 7378, + "colombia": 7379, + "edwards": 7380, + "garage": 7381, + "##mm": 7382, + "recalled": 7383, + "##ball": 7384, + "rage": 7385, + "harm": 7386, + "nigeria": 7387, + "breast": 7388, + "##ren": 7389, + "furniture": 7390, + "pupils": 7391, + "settle": 7392, + "##lus": 7393, + "cuba": 7394, + "balls": 7395, + "client": 7396, + "alaska": 7397, + "21st": 7398, + "linear": 7399, + "thrust": 7400, + "celebration": 7401, + "latino": 7402, + "genetic": 7403, + "terror": 7404, + "##cia": 7405, + "##ening": 7406, + "lightning": 7407, + "fee": 7408, + "witness": 7409, + "lodge": 7410, + "establishing": 7411, + "skull": 7412, + "##ique": 7413, + "earning": 7414, + "hood": 7415, + "##ei": 7416, + "rebellion": 7417, + "wang": 7418, + "sporting": 7419, + "warned": 7420, + "missile": 7421, + "devoted": 7422, + "activist": 7423, + "porch": 7424, + "worship": 7425, + "fourteen": 7426, + "package": 7427, + "1871": 7428, + "decorated": 7429, + "##shire": 7430, + "housed": 7431, + "##ock": 7432, + "chess": 7433, + "sailed": 7434, + "doctors": 7435, + "oscar": 7436, + "joan": 7437, + "treat": 7438, + "garcia": 7439, + "harbour": 7440, + "jeremy": 7441, + "##ire": 7442, + "traditions": 7443, + "dominant": 7444, + "jacques": 7445, + "##gon": 7446, + "##wan": 7447, + "relocated": 7448, + "1879": 7449, + "amendment": 7450, + "sized": 7451, + "companion": 7452, + "simultaneously": 7453, + "volleyball": 7454, + "spun": 7455, + "acre": 7456, + "increases": 7457, + "stopping": 7458, + "loves": 7459, + "belongs": 7460, + "affect": 7461, + "drafted": 7462, + "tossed": 7463, + "scout": 7464, + "battles": 7465, + "1875": 7466, + "filming": 7467, + "shoved": 7468, + "munich": 7469, + "tenure": 7470, + "vertical": 7471, + "romance": 7472, + "pc": 7473, + "##cher": 7474, + "argue": 7475, + "##ical": 7476, + "craft": 7477, + "ranging": 7478, + "www": 7479, + "opens": 7480, + "honest": 7481, + "tyler": 7482, + "yesterday": 7483, + "virtual": 7484, + "##let": 7485, + "muslims": 7486, + "reveal": 7487, + "snake": 7488, + "immigrants": 7489, + "radical": 7490, + "screaming": 7491, + "speakers": 7492, + "firing": 7493, + "saving": 7494, + "belonging": 7495, + "ease": 7496, + "lighting": 7497, + "prefecture": 7498, + "blame": 7499, + "farmer": 7500, + "hungry": 7501, + "grows": 7502, + "rubbed": 7503, + "beam": 7504, + "sur": 7505, + "subsidiary": 7506, + "##cha": 7507, + "armenian": 7508, + "sao": 7509, + "dropping": 7510, + "conventional": 7511, + "##fer": 7512, + "microsoft": 7513, + "reply": 7514, + "qualify": 7515, + "spots": 7516, + "1867": 7517, + "sweat": 7518, + "festivals": 7519, + "##ken": 7520, + "immigration": 7521, + "physician": 7522, + "discover": 7523, + "exposure": 7524, + "sandy": 7525, + "explanation": 7526, + "isaac": 7527, + "implemented": 7528, + "##fish": 7529, + "hart": 7530, + "initiated": 7531, + "connect": 7532, + "stakes": 7533, + "presents": 7534, + "heights": 7535, + "householder": 7536, + "pleased": 7537, + "tourist": 7538, + "regardless": 7539, + "slip": 7540, + "closest": 7541, + "##ction": 7542, + "surely": 7543, + "sultan": 7544, + "brings": 7545, + "riley": 7546, + "preparation": 7547, + "aboard": 7548, + "slammed": 7549, + "baptist": 7550, + "experiment": 7551, + "ongoing": 7552, + "interstate": 7553, + "organic": 7554, + "playoffs": 7555, + "##ika": 7556, + "1877": 7557, + "130": 7558, + "##tar": 7559, + "hindu": 7560, + "error": 7561, + "tours": 7562, + "tier": 7563, + "plenty": 7564, + "arrangements": 7565, + "talks": 7566, + "trapped": 7567, + "excited": 7568, + "sank": 7569, + "ho": 7570, + "athens": 7571, + "1872": 7572, + "denver": 7573, + "welfare": 7574, + "suburb": 7575, + "athletes": 7576, + "trick": 7577, + "diverse": 7578, + "belly": 7579, + "exclusively": 7580, + "yelled": 7581, + "1868": 7582, + "##med": 7583, + "conversion": 7584, + "##ette": 7585, + "1874": 7586, + "internationally": 7587, + "computers": 7588, + "conductor": 7589, + "abilities": 7590, + "sensitive": 7591, + "hello": 7592, + "dispute": 7593, + "measured": 7594, + "globe": 7595, + "rocket": 7596, + "prices": 7597, + "amsterdam": 7598, + "flights": 7599, + "tigers": 7600, + "inn": 7601, + "municipalities": 7602, + "emotion": 7603, + "references": 7604, + "3d": 7605, + "##mus": 7606, + "explains": 7607, + "airlines": 7608, + "manufactured": 7609, + "pm": 7610, + "archaeological": 7611, + "1873": 7612, + "interpretation": 7613, + "devon": 7614, + "comment": 7615, + "##ites": 7616, + "settlements": 7617, + "kissing": 7618, + "absolute": 7619, + "improvement": 7620, + "suite": 7621, + "impressed": 7622, + "barcelona": 7623, + "sullivan": 7624, + "jefferson": 7625, + "towers": 7626, + "jesse": 7627, + "julie": 7628, + "##tin": 7629, + "##lu": 7630, + "grandson": 7631, + "hi": 7632, + "gauge": 7633, + "regard": 7634, + "rings": 7635, + "interviews": 7636, + "trace": 7637, + "raymond": 7638, + "thumb": 7639, + "departments": 7640, + "burns": 7641, + "serial": 7642, + "bulgarian": 7643, + "scores": 7644, + "demonstrated": 7645, + "##ix": 7646, + "1866": 7647, + "kyle": 7648, + "alberta": 7649, + "underneath": 7650, + "romanized": 7651, + "##ward": 7652, + "relieved": 7653, + "acquisition": 7654, + "phrase": 7655, + "cliff": 7656, + "reveals": 7657, + "han": 7658, + "cuts": 7659, + "merger": 7660, + "custom": 7661, + "##dar": 7662, + "nee": 7663, + "gilbert": 7664, + "graduation": 7665, + "##nts": 7666, + "assessment": 7667, + "cafe": 7668, + "difficulty": 7669, + "demands": 7670, + "swung": 7671, + "democrat": 7672, + "jennifer": 7673, + "commons": 7674, + "1940s": 7675, + "grove": 7676, + "##yo": 7677, + "completing": 7678, + "focuses": 7679, + "sum": 7680, + "substitute": 7681, + "bearing": 7682, + "stretch": 7683, + "reception": 7684, + "##py": 7685, + "reflected": 7686, + "essentially": 7687, + "destination": 7688, + "pairs": 7689, + "##ched": 7690, + "survival": 7691, + "resource": 7692, + "##bach": 7693, + "promoting": 7694, + "doubles": 7695, + "messages": 7696, + "tear": 7697, + "##down": 7698, + "##fully": 7699, + "parade": 7700, + "florence": 7701, + "harvey": 7702, + "incumbent": 7703, + "partial": 7704, + "framework": 7705, + "900": 7706, + "pedro": 7707, + "frozen": 7708, + "procedure": 7709, + "olivia": 7710, + "controls": 7711, + "##mic": 7712, + "shelter": 7713, + "personally": 7714, + "temperatures": 7715, + "##od": 7716, + "brisbane": 7717, + "tested": 7718, + "sits": 7719, + "marble": 7720, + "comprehensive": 7721, + "oxygen": 7722, + "leonard": 7723, + "##kov": 7724, + "inaugural": 7725, + "iranian": 7726, + "referring": 7727, + "quarters": 7728, + "attitude": 7729, + "##ivity": 7730, + "mainstream": 7731, + "lined": 7732, + "mars": 7733, + "dakota": 7734, + "norfolk": 7735, + "unsuccessful": 7736, + "##°": 7737, + "explosion": 7738, + "helicopter": 7739, + "congressional": 7740, + "##sing": 7741, + "inspector": 7742, + "bitch": 7743, + "seal": 7744, + "departed": 7745, + "divine": 7746, + "##ters": 7747, + "coaching": 7748, + "examination": 7749, + "punishment": 7750, + "manufacturer": 7751, + "sink": 7752, + "columns": 7753, + "unincorporated": 7754, + "signals": 7755, + "nevada": 7756, + "squeezed": 7757, + "dylan": 7758, + "dining": 7759, + "photos": 7760, + "martial": 7761, + "manuel": 7762, + "eighteen": 7763, + "elevator": 7764, + "brushed": 7765, + "plates": 7766, + "ministers": 7767, + "ivy": 7768, + "congregation": 7769, + "##len": 7770, + "slept": 7771, + "specialized": 7772, + "taxes": 7773, + "curve": 7774, + "restricted": 7775, + "negotiations": 7776, + "likes": 7777, + "statistical": 7778, + "arnold": 7779, + "inspiration": 7780, + "execution": 7781, + "bold": 7782, + "intermediate": 7783, + "significance": 7784, + "margin": 7785, + "ruler": 7786, + "wheels": 7787, + "gothic": 7788, + "intellectual": 7789, + "dependent": 7790, + "listened": 7791, + "eligible": 7792, + "buses": 7793, + "widow": 7794, + "syria": 7795, + "earn": 7796, + "cincinnati": 7797, + "collapsed": 7798, + "recipient": 7799, + "secrets": 7800, + "accessible": 7801, + "philippine": 7802, + "maritime": 7803, + "goddess": 7804, + "clerk": 7805, + "surrender": 7806, + "breaks": 7807, + "playoff": 7808, + "database": 7809, + "##ified": 7810, + "##lon": 7811, + "ideal": 7812, + "beetle": 7813, + "aspect": 7814, + "soap": 7815, + "regulation": 7816, + "strings": 7817, + "expand": 7818, + "anglo": 7819, + "shorter": 7820, + "crosses": 7821, + "retreat": 7822, + "tough": 7823, + "coins": 7824, + "wallace": 7825, + "directions": 7826, + "pressing": 7827, + "##oon": 7828, + "shipping": 7829, + "locomotives": 7830, + "comparison": 7831, + "topics": 7832, + "nephew": 7833, + "##mes": 7834, + "distinction": 7835, + "honors": 7836, + "travelled": 7837, + "sierra": 7838, + "ibn": 7839, + "##over": 7840, + "fortress": 7841, + "sa": 7842, + "recognised": 7843, + "carved": 7844, + "1869": 7845, + "clients": 7846, + "##dan": 7847, + "intent": 7848, + "##mar": 7849, + "coaches": 7850, + "describing": 7851, + "bread": 7852, + "##ington": 7853, + "beaten": 7854, + "northwestern": 7855, + "##ona": 7856, + "merit": 7857, + "youtube": 7858, + "collapse": 7859, + "challenges": 7860, + "em": 7861, + "historians": 7862, + "objective": 7863, + "submitted": 7864, + "virus": 7865, + "attacking": 7866, + "drake": 7867, + "assume": 7868, + "##ere": 7869, + "diseases": 7870, + "marc": 7871, + "stem": 7872, + "leeds": 7873, + "##cus": 7874, + "##ab": 7875, + "farming": 7876, + "glasses": 7877, + "##lock": 7878, + "visits": 7879, + "nowhere": 7880, + "fellowship": 7881, + "relevant": 7882, + "carries": 7883, + "restaurants": 7884, + "experiments": 7885, + "101": 7886, + "constantly": 7887, + "bases": 7888, + "targets": 7889, + "shah": 7890, + "tenth": 7891, + "opponents": 7892, + "verse": 7893, + "territorial": 7894, + "##ira": 7895, + "writings": 7896, + "corruption": 7897, + "##hs": 7898, + "instruction": 7899, + "inherited": 7900, + "reverse": 7901, + "emphasis": 7902, + "##vic": 7903, + "employee": 7904, + "arch": 7905, + "keeps": 7906, + "rabbi": 7907, + "watson": 7908, + "payment": 7909, + "uh": 7910, + "##ala": 7911, + "nancy": 7912, + "##tre": 7913, + "venice": 7914, + "fastest": 7915, + "sexy": 7916, + "banned": 7917, + "adrian": 7918, + "properly": 7919, + "ruth": 7920, + "touchdown": 7921, + "dollar": 7922, + "boards": 7923, + "metre": 7924, + "circles": 7925, + "edges": 7926, + "favour": 7927, + "comments": 7928, + "ok": 7929, + "travels": 7930, + "liberation": 7931, + "scattered": 7932, + "firmly": 7933, + "##ular": 7934, + "holland": 7935, + "permitted": 7936, + "diesel": 7937, + "kenya": 7938, + "den": 7939, + "originated": 7940, + "##ral": 7941, + "demons": 7942, + "resumed": 7943, + "dragged": 7944, + "rider": 7945, + "##rus": 7946, + "servant": 7947, + "blinked": 7948, + "extend": 7949, + "torn": 7950, + "##ias": 7951, + "##sey": 7952, + "input": 7953, + "meal": 7954, + "everybody": 7955, + "cylinder": 7956, + "kinds": 7957, + "camps": 7958, + "##fe": 7959, + "bullet": 7960, + "logic": 7961, + "##wn": 7962, + "croatian": 7963, + "evolved": 7964, + "healthy": 7965, + "fool": 7966, + "chocolate": 7967, + "wise": 7968, + "preserve": 7969, + "pradesh": 7970, + "##ess": 7971, + "respective": 7972, + "1850": 7973, + "##ew": 7974, + "chicken": 7975, + "artificial": 7976, + "gross": 7977, + "corresponding": 7978, + "convicted": 7979, + "cage": 7980, + "caroline": 7981, + "dialogue": 7982, + "##dor": 7983, + "narrative": 7984, + "stranger": 7985, + "mario": 7986, + "br": 7987, + "christianity": 7988, + "failing": 7989, + "trent": 7990, + "commanding": 7991, + "buddhist": 7992, + "1848": 7993, + "maurice": 7994, + "focusing": 7995, + "yale": 7996, + "bike": 7997, + "altitude": 7998, + "##ering": 7999, + "mouse": 8000, + "revised": 8001, + "##sley": 8002, + "veteran": 8003, + "##ig": 8004, + "pulls": 8005, + "theology": 8006, + "crashed": 8007, + "campaigns": 8008, + "legion": 8009, + "##ability": 8010, + "drag": 8011, + "excellence": 8012, + "customer": 8013, + "cancelled": 8014, + "intensity": 8015, + "excuse": 8016, + "##lar": 8017, + "liga": 8018, + "participating": 8019, + "contributing": 8020, + "printing": 8021, + "##burn": 8022, + "variable": 8023, + "##rk": 8024, + "curious": 8025, + "bin": 8026, + "legacy": 8027, + "renaissance": 8028, + "##my": 8029, + "symptoms": 8030, + "binding": 8031, + "vocalist": 8032, + "dancer": 8033, + "##nie": 8034, + "grammar": 8035, + "gospel": 8036, + "democrats": 8037, + "ya": 8038, + "enters": 8039, + "sc": 8040, + "diplomatic": 8041, + "hitler": 8042, + "##ser": 8043, + "clouds": 8044, + "mathematical": 8045, + "quit": 8046, + "defended": 8047, + "oriented": 8048, + "##heim": 8049, + "fundamental": 8050, + "hardware": 8051, + "impressive": 8052, + "equally": 8053, + "convince": 8054, + "confederate": 8055, + "guilt": 8056, + "chuck": 8057, + "sliding": 8058, + "##ware": 8059, + "magnetic": 8060, + "narrowed": 8061, + "petersburg": 8062, + "bulgaria": 8063, + "otto": 8064, + "phd": 8065, + "skill": 8066, + "##ama": 8067, + "reader": 8068, + "hopes": 8069, + "pitcher": 8070, + "reservoir": 8071, + "hearts": 8072, + "automatically": 8073, + "expecting": 8074, + "mysterious": 8075, + "bennett": 8076, + "extensively": 8077, + "imagined": 8078, + "seeds": 8079, + "monitor": 8080, + "fix": 8081, + "##ative": 8082, + "journalism": 8083, + "struggling": 8084, + "signature": 8085, + "ranch": 8086, + "encounter": 8087, + "photographer": 8088, + "observation": 8089, + "protests": 8090, + "##pin": 8091, + "influences": 8092, + "##hr": 8093, + "calendar": 8094, + "##all": 8095, + "cruz": 8096, + "croatia": 8097, + "locomotive": 8098, + "hughes": 8099, + "naturally": 8100, + "shakespeare": 8101, + "basement": 8102, + "hook": 8103, + "uncredited": 8104, + "faded": 8105, + "theories": 8106, + "approaches": 8107, + "dare": 8108, + "phillips": 8109, + "filling": 8110, + "fury": 8111, + "obama": 8112, + "##ain": 8113, + "efficient": 8114, + "arc": 8115, + "deliver": 8116, + "min": 8117, + "raid": 8118, + "breeding": 8119, + "inducted": 8120, + "leagues": 8121, + "efficiency": 8122, + "axis": 8123, + "montana": 8124, + "eagles": 8125, + "##ked": 8126, + "supplied": 8127, + "instructions": 8128, + "karen": 8129, + "picking": 8130, + "indicating": 8131, + "trap": 8132, + "anchor": 8133, + "practically": 8134, + "christians": 8135, + "tomb": 8136, + "vary": 8137, + "occasional": 8138, + "electronics": 8139, + "lords": 8140, + "readers": 8141, + "newcastle": 8142, + "faint": 8143, + "innovation": 8144, + "collect": 8145, + "situations": 8146, + "engagement": 8147, + "160": 8148, + "claude": 8149, + "mixture": 8150, + "##feld": 8151, + "peer": 8152, + "tissue": 8153, + "logo": 8154, + "lean": 8155, + "##ration": 8156, + "°f": 8157, + "floors": 8158, + "##ven": 8159, + "architects": 8160, + "reducing": 8161, + "##our": 8162, + "##ments": 8163, + "rope": 8164, + "1859": 8165, + "ottawa": 8166, + "##har": 8167, + "samples": 8168, + "banking": 8169, + "declaration": 8170, + "proteins": 8171, + "resignation": 8172, + "francois": 8173, + "saudi": 8174, + "advocate": 8175, + "exhibited": 8176, + "armor": 8177, + "twins": 8178, + "divorce": 8179, + "##ras": 8180, + "abraham": 8181, + "reviewed": 8182, + "jo": 8183, + "temporarily": 8184, + "matrix": 8185, + "physically": 8186, + "pulse": 8187, + "curled": 8188, + "##ena": 8189, + "difficulties": 8190, + "bengal": 8191, + "usage": 8192, + "##ban": 8193, + "annie": 8194, + "riders": 8195, + "certificate": 8196, + "##pi": 8197, + "holes": 8198, + "warsaw": 8199, + "distinctive": 8200, + "jessica": 8201, + "##mon": 8202, + "mutual": 8203, + "1857": 8204, + "customs": 8205, + "circular": 8206, + "eugene": 8207, + "removal": 8208, + "loaded": 8209, + "mere": 8210, + "vulnerable": 8211, + "depicted": 8212, + "generations": 8213, + "dame": 8214, + "heir": 8215, + "enormous": 8216, + "lightly": 8217, + "climbing": 8218, + "pitched": 8219, + "lessons": 8220, + "pilots": 8221, + "nepal": 8222, + "ram": 8223, + "google": 8224, + "preparing": 8225, + "brad": 8226, + "louise": 8227, + "renowned": 8228, + "##₂": 8229, + "liam": 8230, + "##ably": 8231, + "plaza": 8232, + "shaw": 8233, + "sophie": 8234, + "brilliant": 8235, + "bills": 8236, + "##bar": 8237, + "##nik": 8238, + "fucking": 8239, + "mainland": 8240, + "server": 8241, + "pleasant": 8242, + "seized": 8243, + "veterans": 8244, + "jerked": 8245, + "fail": 8246, + "beta": 8247, + "brush": 8248, + "radiation": 8249, + "stored": 8250, + "warmth": 8251, + "southeastern": 8252, + "nate": 8253, + "sin": 8254, + "raced": 8255, + "berkeley": 8256, + "joke": 8257, + "athlete": 8258, + "designation": 8259, + "trunk": 8260, + "##low": 8261, + "roland": 8262, + "qualification": 8263, + "archives": 8264, + "heels": 8265, + "artwork": 8266, + "receives": 8267, + "judicial": 8268, + "reserves": 8269, + "##bed": 8270, + "woke": 8271, + "installation": 8272, + "abu": 8273, + "floating": 8274, + "fake": 8275, + "lesser": 8276, + "excitement": 8277, + "interface": 8278, + "concentrated": 8279, + "addressed": 8280, + "characteristic": 8281, + "amanda": 8282, + "saxophone": 8283, + "monk": 8284, + "auto": 8285, + "##bus": 8286, + "releasing": 8287, + "egg": 8288, + "dies": 8289, + "interaction": 8290, + "defender": 8291, + "ce": 8292, + "outbreak": 8293, + "glory": 8294, + "loving": 8295, + "##bert": 8296, + "sequel": 8297, + "consciousness": 8298, + "http": 8299, + "awake": 8300, + "ski": 8301, + "enrolled": 8302, + "##ress": 8303, + "handling": 8304, + "rookie": 8305, + "brow": 8306, + "somebody": 8307, + "biography": 8308, + "warfare": 8309, + "amounts": 8310, + "contracts": 8311, + "presentation": 8312, + "fabric": 8313, + "dissolved": 8314, + "challenged": 8315, + "meter": 8316, + "psychological": 8317, + "lt": 8318, + "elevated": 8319, + "rally": 8320, + "accurate": 8321, + "##tha": 8322, + "hospitals": 8323, + "undergraduate": 8324, + "specialist": 8325, + "venezuela": 8326, + "exhibit": 8327, + "shed": 8328, + "nursing": 8329, + "protestant": 8330, + "fluid": 8331, + "structural": 8332, + "footage": 8333, + "jared": 8334, + "consistent": 8335, + "prey": 8336, + "##ska": 8337, + "succession": 8338, + "reflect": 8339, + "exile": 8340, + "lebanon": 8341, + "wiped": 8342, + "suspect": 8343, + "shanghai": 8344, + "resting": 8345, + "integration": 8346, + "preservation": 8347, + "marvel": 8348, + "variant": 8349, + "pirates": 8350, + "sheep": 8351, + "rounded": 8352, + "capita": 8353, + "sailing": 8354, + "colonies": 8355, + "manuscript": 8356, + "deemed": 8357, + "variations": 8358, + "clarke": 8359, + "functional": 8360, + "emerging": 8361, + "boxing": 8362, + "relaxed": 8363, + "curse": 8364, + "azerbaijan": 8365, + "heavyweight": 8366, + "nickname": 8367, + "editorial": 8368, + "rang": 8369, + "grid": 8370, + "tightened": 8371, + "earthquake": 8372, + "flashed": 8373, + "miguel": 8374, + "rushing": 8375, + "##ches": 8376, + "improvements": 8377, + "boxes": 8378, + "brooks": 8379, + "180": 8380, + "consumption": 8381, + "molecular": 8382, + "felix": 8383, + "societies": 8384, + "repeatedly": 8385, + "variation": 8386, + "aids": 8387, + "civic": 8388, + "graphics": 8389, + "professionals": 8390, + "realm": 8391, + "autonomous": 8392, + "receiver": 8393, + "delayed": 8394, + "workshop": 8395, + "militia": 8396, + "chairs": 8397, + "trump": 8398, + "canyon": 8399, + "##point": 8400, + "harsh": 8401, + "extending": 8402, + "lovely": 8403, + "happiness": 8404, + "##jan": 8405, + "stake": 8406, + "eyebrows": 8407, + "embassy": 8408, + "wellington": 8409, + "hannah": 8410, + "##ella": 8411, + "sony": 8412, + "corners": 8413, + "bishops": 8414, + "swear": 8415, + "cloth": 8416, + "contents": 8417, + "xi": 8418, + "namely": 8419, + "commenced": 8420, + "1854": 8421, + "stanford": 8422, + "nashville": 8423, + "courage": 8424, + "graphic": 8425, + "commitment": 8426, + "garrison": 8427, + "##bin": 8428, + "hamlet": 8429, + "clearing": 8430, + "rebels": 8431, + "attraction": 8432, + "literacy": 8433, + "cooking": 8434, + "ruins": 8435, + "temples": 8436, + "jenny": 8437, + "humanity": 8438, + "celebrate": 8439, + "hasn": 8440, + "freight": 8441, + "sixty": 8442, + "rebel": 8443, + "bastard": 8444, + "##art": 8445, + "newton": 8446, + "##ada": 8447, + "deer": 8448, + "##ges": 8449, + "##ching": 8450, + "smiles": 8451, + "delaware": 8452, + "singers": 8453, + "##ets": 8454, + "approaching": 8455, + "assists": 8456, + "flame": 8457, + "##ph": 8458, + "boulevard": 8459, + "barrel": 8460, + "planted": 8461, + "##ome": 8462, + "pursuit": 8463, + "##sia": 8464, + "consequences": 8465, + "posts": 8466, + "shallow": 8467, + "invitation": 8468, + "rode": 8469, + "depot": 8470, + "ernest": 8471, + "kane": 8472, + "rod": 8473, + "concepts": 8474, + "preston": 8475, + "topic": 8476, + "chambers": 8477, + "striking": 8478, + "blast": 8479, + "arrives": 8480, + "descendants": 8481, + "montgomery": 8482, + "ranges": 8483, + "worlds": 8484, + "##lay": 8485, + "##ari": 8486, + "span": 8487, + "chaos": 8488, + "praise": 8489, + "##ag": 8490, + "fewer": 8491, + "1855": 8492, + "sanctuary": 8493, + "mud": 8494, + "fbi": 8495, + "##ions": 8496, + "programmes": 8497, + "maintaining": 8498, + "unity": 8499, + "harper": 8500, + "bore": 8501, + "handsome": 8502, + "closure": 8503, + "tournaments": 8504, + "thunder": 8505, + "nebraska": 8506, + "linda": 8507, + "facade": 8508, + "puts": 8509, + "satisfied": 8510, + "argentine": 8511, + "dale": 8512, + "cork": 8513, + "dome": 8514, + "panama": 8515, + "##yl": 8516, + "1858": 8517, + "tasks": 8518, + "experts": 8519, + "##ates": 8520, + "feeding": 8521, + "equation": 8522, + "##las": 8523, + "##ida": 8524, + "##tu": 8525, + "engage": 8526, + "bryan": 8527, + "##ax": 8528, + "um": 8529, + "quartet": 8530, + "melody": 8531, + "disbanded": 8532, + "sheffield": 8533, + "blocked": 8534, + "gasped": 8535, + "delay": 8536, + "kisses": 8537, + "maggie": 8538, + "connects": 8539, + "##non": 8540, + "sts": 8541, + "poured": 8542, + "creator": 8543, + "publishers": 8544, + "##we": 8545, + "guided": 8546, + "ellis": 8547, + "extinct": 8548, + "hug": 8549, + "gaining": 8550, + "##ord": 8551, + "complicated": 8552, + "##bility": 8553, + "poll": 8554, + "clenched": 8555, + "investigate": 8556, + "##use": 8557, + "thereby": 8558, + "quantum": 8559, + "spine": 8560, + "cdp": 8561, + "humor": 8562, + "kills": 8563, + "administered": 8564, + "semifinals": 8565, + "##du": 8566, + "encountered": 8567, + "ignore": 8568, + "##bu": 8569, + "commentary": 8570, + "##maker": 8571, + "bother": 8572, + "roosevelt": 8573, + "140": 8574, + "plains": 8575, + "halfway": 8576, + "flowing": 8577, + "cultures": 8578, + "crack": 8579, + "imprisoned": 8580, + "neighboring": 8581, + "airline": 8582, + "##ses": 8583, + "##view": 8584, + "##mate": 8585, + "##ec": 8586, + "gather": 8587, + "wolves": 8588, + "marathon": 8589, + "transformed": 8590, + "##ill": 8591, + "cruise": 8592, + "organisations": 8593, + "carol": 8594, + "punch": 8595, + "exhibitions": 8596, + "numbered": 8597, + "alarm": 8598, + "ratings": 8599, + "daddy": 8600, + "silently": 8601, + "##stein": 8602, + "queens": 8603, + "colours": 8604, + "impression": 8605, + "guidance": 8606, + "liu": 8607, + "tactical": 8608, + "##rat": 8609, + "marshal": 8610, + "della": 8611, + "arrow": 8612, + "##ings": 8613, + "rested": 8614, + "feared": 8615, + "tender": 8616, + "owns": 8617, + "bitter": 8618, + "advisor": 8619, + "escort": 8620, + "##ides": 8621, + "spare": 8622, + "farms": 8623, + "grants": 8624, + "##ene": 8625, + "dragons": 8626, + "encourage": 8627, + "colleagues": 8628, + "cameras": 8629, + "##und": 8630, + "sucked": 8631, + "pile": 8632, + "spirits": 8633, + "prague": 8634, + "statements": 8635, + "suspension": 8636, + "landmark": 8637, + "fence": 8638, + "torture": 8639, + "recreation": 8640, + "bags": 8641, + "permanently": 8642, + "survivors": 8643, + "pond": 8644, + "spy": 8645, + "predecessor": 8646, + "bombing": 8647, + "coup": 8648, + "##og": 8649, + "protecting": 8650, + "transformation": 8651, + "glow": 8652, + "##lands": 8653, + "##book": 8654, + "dug": 8655, + "priests": 8656, + "andrea": 8657, + "feat": 8658, + "barn": 8659, + "jumping": 8660, + "##chen": 8661, + "##ologist": 8662, + "##con": 8663, + "casualties": 8664, + "stern": 8665, + "auckland": 8666, + "pipe": 8667, + "serie": 8668, + "revealing": 8669, + "ba": 8670, + "##bel": 8671, + "trevor": 8672, + "mercy": 8673, + "spectrum": 8674, + "yang": 8675, + "consist": 8676, + "governing": 8677, + "collaborated": 8678, + "possessed": 8679, + "epic": 8680, + "comprises": 8681, + "blew": 8682, + "shane": 8683, + "##ack": 8684, + "lopez": 8685, + "honored": 8686, + "magical": 8687, + "sacrifice": 8688, + "judgment": 8689, + "perceived": 8690, + "hammer": 8691, + "mtv": 8692, + "baronet": 8693, + "tune": 8694, + "das": 8695, + "missionary": 8696, + "sheets": 8697, + "350": 8698, + "neutral": 8699, + "oral": 8700, + "threatening": 8701, + "attractive": 8702, + "shade": 8703, + "aims": 8704, + "seminary": 8705, + "##master": 8706, + "estates": 8707, + "1856": 8708, + "michel": 8709, + "wounds": 8710, + "refugees": 8711, + "manufacturers": 8712, + "##nic": 8713, + "mercury": 8714, + "syndrome": 8715, + "porter": 8716, + "##iya": 8717, + "##din": 8718, + "hamburg": 8719, + "identification": 8720, + "upstairs": 8721, + "purse": 8722, + "widened": 8723, + "pause": 8724, + "cared": 8725, + "breathed": 8726, + "affiliate": 8727, + "santiago": 8728, + "prevented": 8729, + "celtic": 8730, + "fisher": 8731, + "125": 8732, + "recruited": 8733, + "byzantine": 8734, + "reconstruction": 8735, + "farther": 8736, + "##mp": 8737, + "diet": 8738, + "sake": 8739, + "au": 8740, + "spite": 8741, + "sensation": 8742, + "##ert": 8743, + "blank": 8744, + "separation": 8745, + "105": 8746, + "##hon": 8747, + "vladimir": 8748, + "armies": 8749, + "anime": 8750, + "##lie": 8751, + "accommodate": 8752, + "orbit": 8753, + "cult": 8754, + "sofia": 8755, + "archive": 8756, + "##ify": 8757, + "##box": 8758, + "founders": 8759, + "sustained": 8760, + "disorder": 8761, + "honours": 8762, + "northeastern": 8763, + "mia": 8764, + "crops": 8765, + "violet": 8766, + "threats": 8767, + "blanket": 8768, + "fires": 8769, + "canton": 8770, + "followers": 8771, + "southwestern": 8772, + "prototype": 8773, + "voyage": 8774, + "assignment": 8775, + "altered": 8776, + "moderate": 8777, + "protocol": 8778, + "pistol": 8779, + "##eo": 8780, + "questioned": 8781, + "brass": 8782, + "lifting": 8783, + "1852": 8784, + "math": 8785, + "authored": 8786, + "##ual": 8787, + "doug": 8788, + "dimensional": 8789, + "dynamic": 8790, + "##san": 8791, + "1851": 8792, + "pronounced": 8793, + "grateful": 8794, + "quest": 8795, + "uncomfortable": 8796, + "boom": 8797, + "presidency": 8798, + "stevens": 8799, + "relating": 8800, + "politicians": 8801, + "chen": 8802, + "barrier": 8803, + "quinn": 8804, + "diana": 8805, + "mosque": 8806, + "tribal": 8807, + "cheese": 8808, + "palmer": 8809, + "portions": 8810, + "sometime": 8811, + "chester": 8812, + "treasure": 8813, + "wu": 8814, + "bend": 8815, + "download": 8816, + "millions": 8817, + "reforms": 8818, + "registration": 8819, + "##osa": 8820, + "consequently": 8821, + "monitoring": 8822, + "ate": 8823, + "preliminary": 8824, + "brandon": 8825, + "invented": 8826, + "ps": 8827, + "eaten": 8828, + "exterior": 8829, + "intervention": 8830, + "ports": 8831, + "documented": 8832, + "log": 8833, + "displays": 8834, + "lecture": 8835, + "sally": 8836, + "favourite": 8837, + "##itz": 8838, + "vermont": 8839, + "lo": 8840, + "invisible": 8841, + "isle": 8842, + "breed": 8843, + "##ator": 8844, + "journalists": 8845, + "relay": 8846, + "speaks": 8847, + "backward": 8848, + "explore": 8849, + "midfielder": 8850, + "actively": 8851, + "stefan": 8852, + "procedures": 8853, + "cannon": 8854, + "blond": 8855, + "kenneth": 8856, + "centered": 8857, + "servants": 8858, + "chains": 8859, + "libraries": 8860, + "malcolm": 8861, + "essex": 8862, + "henri": 8863, + "slavery": 8864, + "##hal": 8865, + "facts": 8866, + "fairy": 8867, + "coached": 8868, + "cassie": 8869, + "cats": 8870, + "washed": 8871, + "cop": 8872, + "##fi": 8873, + "announcement": 8874, + "item": 8875, + "2000s": 8876, + "vinyl": 8877, + "activated": 8878, + "marco": 8879, + "frontier": 8880, + "growled": 8881, + "curriculum": 8882, + "##das": 8883, + "loyal": 8884, + "accomplished": 8885, + "leslie": 8886, + "ritual": 8887, + "kenny": 8888, + "##00": 8889, + "vii": 8890, + "napoleon": 8891, + "hollow": 8892, + "hybrid": 8893, + "jungle": 8894, + "stationed": 8895, + "friedrich": 8896, + "counted": 8897, + "##ulated": 8898, + "platinum": 8899, + "theatrical": 8900, + "seated": 8901, + "col": 8902, + "rubber": 8903, + "glen": 8904, + "1840": 8905, + "diversity": 8906, + "healing": 8907, + "extends": 8908, + "id": 8909, + "provisions": 8910, + "administrator": 8911, + "columbus": 8912, + "##oe": 8913, + "tributary": 8914, + "te": 8915, + "assured": 8916, + "org": 8917, + "##uous": 8918, + "prestigious": 8919, + "examined": 8920, + "lectures": 8921, + "grammy": 8922, + "ronald": 8923, + "associations": 8924, + "bailey": 8925, + "allan": 8926, + "essays": 8927, + "flute": 8928, + "believing": 8929, + "consultant": 8930, + "proceedings": 8931, + "travelling": 8932, + "1853": 8933, + "kit": 8934, + "kerala": 8935, + "yugoslavia": 8936, + "buddy": 8937, + "methodist": 8938, + "##ith": 8939, + "burial": 8940, + "centres": 8941, + "batman": 8942, + "##nda": 8943, + "discontinued": 8944, + "bo": 8945, + "dock": 8946, + "stockholm": 8947, + "lungs": 8948, + "severely": 8949, + "##nk": 8950, + "citing": 8951, + "manga": 8952, + "##ugh": 8953, + "steal": 8954, + "mumbai": 8955, + "iraqi": 8956, + "robot": 8957, + "celebrity": 8958, + "bride": 8959, + "broadcasts": 8960, + "abolished": 8961, + "pot": 8962, + "joel": 8963, + "overhead": 8964, + "franz": 8965, + "packed": 8966, + "reconnaissance": 8967, + "johann": 8968, + "acknowledged": 8969, + "introduce": 8970, + "handled": 8971, + "doctorate": 8972, + "developments": 8973, + "drinks": 8974, + "alley": 8975, + "palestine": 8976, + "##nis": 8977, + "##aki": 8978, + "proceeded": 8979, + "recover": 8980, + "bradley": 8981, + "grain": 8982, + "patch": 8983, + "afford": 8984, + "infection": 8985, + "nationalist": 8986, + "legendary": 8987, + "##ath": 8988, + "interchange": 8989, + "virtually": 8990, + "gen": 8991, + "gravity": 8992, + "exploration": 8993, + "amber": 8994, + "vital": 8995, + "wishes": 8996, + "powell": 8997, + "doctrine": 8998, + "elbow": 8999, + "screenplay": 9000, + "##bird": 9001, + "contribute": 9002, + "indonesian": 9003, + "pet": 9004, + "creates": 9005, + "##com": 9006, + "enzyme": 9007, + "kylie": 9008, + "discipline": 9009, + "drops": 9010, + "manila": 9011, + "hunger": 9012, + "##ien": 9013, + "layers": 9014, + "suffer": 9015, + "fever": 9016, + "bits": 9017, + "monica": 9018, + "keyboard": 9019, + "manages": 9020, + "##hood": 9021, + "searched": 9022, + "appeals": 9023, + "##bad": 9024, + "testament": 9025, + "grande": 9026, + "reid": 9027, + "##war": 9028, + "beliefs": 9029, + "congo": 9030, + "##ification": 9031, + "##dia": 9032, + "si": 9033, + "requiring": 9034, + "##via": 9035, + "casey": 9036, + "1849": 9037, + "regret": 9038, + "streak": 9039, + "rape": 9040, + "depends": 9041, + "syrian": 9042, + "sprint": 9043, + "pound": 9044, + "tourists": 9045, + "upcoming": 9046, + "pub": 9047, + "##xi": 9048, + "tense": 9049, + "##els": 9050, + "practiced": 9051, + "echo": 9052, + "nationwide": 9053, + "guild": 9054, + "motorcycle": 9055, + "liz": 9056, + "##zar": 9057, + "chiefs": 9058, + "desired": 9059, + "elena": 9060, + "bye": 9061, + "precious": 9062, + "absorbed": 9063, + "relatives": 9064, + "booth": 9065, + "pianist": 9066, + "##mal": 9067, + "citizenship": 9068, + "exhausted": 9069, + "wilhelm": 9070, + "##ceae": 9071, + "##hed": 9072, + "noting": 9073, + "quarterback": 9074, + "urge": 9075, + "hectares": 9076, + "##gue": 9077, + "ace": 9078, + "holly": 9079, + "##tal": 9080, + "blonde": 9081, + "davies": 9082, + "parked": 9083, + "sustainable": 9084, + "stepping": 9085, + "twentieth": 9086, + "airfield": 9087, + "galaxy": 9088, + "nest": 9089, + "chip": 9090, + "##nell": 9091, + "tan": 9092, + "shaft": 9093, + "paulo": 9094, + "requirement": 9095, + "##zy": 9096, + "paradise": 9097, + "tobacco": 9098, + "trans": 9099, + "renewed": 9100, + "vietnamese": 9101, + "##cker": 9102, + "##ju": 9103, + "suggesting": 9104, + "catching": 9105, + "holmes": 9106, + "enjoying": 9107, + "md": 9108, + "trips": 9109, + "colt": 9110, + "holder": 9111, + "butterfly": 9112, + "nerve": 9113, + "reformed": 9114, + "cherry": 9115, + "bowling": 9116, + "trailer": 9117, + "carriage": 9118, + "goodbye": 9119, + "appreciate": 9120, + "toy": 9121, + "joshua": 9122, + "interactive": 9123, + "enabled": 9124, + "involve": 9125, + "##kan": 9126, + "collar": 9127, + "determination": 9128, + "bunch": 9129, + "facebook": 9130, + "recall": 9131, + "shorts": 9132, + "superintendent": 9133, + "episcopal": 9134, + "frustration": 9135, + "giovanni": 9136, + "nineteenth": 9137, + "laser": 9138, + "privately": 9139, + "array": 9140, + "circulation": 9141, + "##ovic": 9142, + "armstrong": 9143, + "deals": 9144, + "painful": 9145, + "permit": 9146, + "discrimination": 9147, + "##wi": 9148, + "aires": 9149, + "retiring": 9150, + "cottage": 9151, + "ni": 9152, + "##sta": 9153, + "horizon": 9154, + "ellen": 9155, + "jamaica": 9156, + "ripped": 9157, + "fernando": 9158, + "chapters": 9159, + "playstation": 9160, + "patron": 9161, + "lecturer": 9162, + "navigation": 9163, + "behaviour": 9164, + "genes": 9165, + "georgian": 9166, + "export": 9167, + "solomon": 9168, + "rivals": 9169, + "swift": 9170, + "seventeen": 9171, + "rodriguez": 9172, + "princeton": 9173, + "independently": 9174, + "sox": 9175, + "1847": 9176, + "arguing": 9177, + "entity": 9178, + "casting": 9179, + "hank": 9180, + "criteria": 9181, + "oakland": 9182, + "geographic": 9183, + "milwaukee": 9184, + "reflection": 9185, + "expanding": 9186, + "conquest": 9187, + "dubbed": 9188, + "##tv": 9189, + "halt": 9190, + "brave": 9191, + "brunswick": 9192, + "doi": 9193, + "arched": 9194, + "curtis": 9195, + "divorced": 9196, + "predominantly": 9197, + "somerset": 9198, + "streams": 9199, + "ugly": 9200, + "zoo": 9201, + "horrible": 9202, + "curved": 9203, + "buenos": 9204, + "fierce": 9205, + "dictionary": 9206, + "vector": 9207, + "theological": 9208, + "unions": 9209, + "handful": 9210, + "stability": 9211, + "chan": 9212, + "punjab": 9213, + "segments": 9214, + "##lly": 9215, + "altar": 9216, + "ignoring": 9217, + "gesture": 9218, + "monsters": 9219, + "pastor": 9220, + "##stone": 9221, + "thighs": 9222, + "unexpected": 9223, + "operators": 9224, + "abruptly": 9225, + "coin": 9226, + "compiled": 9227, + "associates": 9228, + "improving": 9229, + "migration": 9230, + "pin": 9231, + "##ose": 9232, + "compact": 9233, + "collegiate": 9234, + "reserved": 9235, + "##urs": 9236, + "quarterfinals": 9237, + "roster": 9238, + "restore": 9239, + "assembled": 9240, + "hurry": 9241, + "oval": 9242, + "##cies": 9243, + "1846": 9244, + "flags": 9245, + "martha": 9246, + "##del": 9247, + "victories": 9248, + "sharply": 9249, + "##rated": 9250, + "argues": 9251, + "deadly": 9252, + "neo": 9253, + "drawings": 9254, + "symbols": 9255, + "performer": 9256, + "##iel": 9257, + "griffin": 9258, + "restrictions": 9259, + "editing": 9260, + "andrews": 9261, + "java": 9262, + "journals": 9263, + "arabia": 9264, + "compositions": 9265, + "dee": 9266, + "pierce": 9267, + "removing": 9268, + "hindi": 9269, + "casino": 9270, + "runway": 9271, + "civilians": 9272, + "minds": 9273, + "nasa": 9274, + "hotels": 9275, + "##zation": 9276, + "refuge": 9277, + "rent": 9278, + "retain": 9279, + "potentially": 9280, + "conferences": 9281, + "suburban": 9282, + "conducting": 9283, + "##tto": 9284, + "##tions": 9285, + "##tle": 9286, + "descended": 9287, + "massacre": 9288, + "##cal": 9289, + "ammunition": 9290, + "terrain": 9291, + "fork": 9292, + "souls": 9293, + "counts": 9294, + "chelsea": 9295, + "durham": 9296, + "drives": 9297, + "cab": 9298, + "##bank": 9299, + "perth": 9300, + "realizing": 9301, + "palestinian": 9302, + "finn": 9303, + "simpson": 9304, + "##dal": 9305, + "betty": 9306, + "##ule": 9307, + "moreover": 9308, + "particles": 9309, + "cardinals": 9310, + "tent": 9311, + "evaluation": 9312, + "extraordinary": 9313, + "##oid": 9314, + "inscription": 9315, + "##works": 9316, + "wednesday": 9317, + "chloe": 9318, + "maintains": 9319, + "panels": 9320, + "ashley": 9321, + "trucks": 9322, + "##nation": 9323, + "cluster": 9324, + "sunlight": 9325, + "strikes": 9326, + "zhang": 9327, + "##wing": 9328, + "dialect": 9329, + "canon": 9330, + "##ap": 9331, + "tucked": 9332, + "##ws": 9333, + "collecting": 9334, + "##mas": 9335, + "##can": 9336, + "##sville": 9337, + "maker": 9338, + "quoted": 9339, + "evan": 9340, + "franco": 9341, + "aria": 9342, + "buying": 9343, + "cleaning": 9344, + "eva": 9345, + "closet": 9346, + "provision": 9347, + "apollo": 9348, + "clinic": 9349, + "rat": 9350, + "##ez": 9351, + "necessarily": 9352, + "ac": 9353, + "##gle": 9354, + "##ising": 9355, + "venues": 9356, + "flipped": 9357, + "cent": 9358, + "spreading": 9359, + "trustees": 9360, + "checking": 9361, + "authorized": 9362, + "##sco": 9363, + "disappointed": 9364, + "##ado": 9365, + "notion": 9366, + "duration": 9367, + "trumpet": 9368, + "hesitated": 9369, + "topped": 9370, + "brussels": 9371, + "rolls": 9372, + "theoretical": 9373, + "hint": 9374, + "define": 9375, + "aggressive": 9376, + "repeat": 9377, + "wash": 9378, + "peaceful": 9379, + "optical": 9380, + "width": 9381, + "allegedly": 9382, + "mcdonald": 9383, + "strict": 9384, + "copyright": 9385, + "##illa": 9386, + "investors": 9387, + "mar": 9388, + "jam": 9389, + "witnesses": 9390, + "sounding": 9391, + "miranda": 9392, + "michelle": 9393, + "privacy": 9394, + "hugo": 9395, + "harmony": 9396, + "##pp": 9397, + "valid": 9398, + "lynn": 9399, + "glared": 9400, + "nina": 9401, + "102": 9402, + "headquartered": 9403, + "diving": 9404, + "boarding": 9405, + "gibson": 9406, + "##ncy": 9407, + "albanian": 9408, + "marsh": 9409, + "routine": 9410, + "dealt": 9411, + "enhanced": 9412, + "er": 9413, + "intelligent": 9414, + "substance": 9415, + "targeted": 9416, + "enlisted": 9417, + "discovers": 9418, + "spinning": 9419, + "observations": 9420, + "pissed": 9421, + "smoking": 9422, + "rebecca": 9423, + "capitol": 9424, + "visa": 9425, + "varied": 9426, + "costume": 9427, + "seemingly": 9428, + "indies": 9429, + "compensation": 9430, + "surgeon": 9431, + "thursday": 9432, + "arsenal": 9433, + "westminster": 9434, + "suburbs": 9435, + "rid": 9436, + "anglican": 9437, + "##ridge": 9438, + "knots": 9439, + "foods": 9440, + "alumni": 9441, + "lighter": 9442, + "fraser": 9443, + "whoever": 9444, + "portal": 9445, + "scandal": 9446, + "##ray": 9447, + "gavin": 9448, + "advised": 9449, + "instructor": 9450, + "flooding": 9451, + "terrorist": 9452, + "##ale": 9453, + "teenage": 9454, + "interim": 9455, + "senses": 9456, + "duck": 9457, + "teen": 9458, + "thesis": 9459, + "abby": 9460, + "eager": 9461, + "overcome": 9462, + "##ile": 9463, + "newport": 9464, + "glenn": 9465, + "rises": 9466, + "shame": 9467, + "##cc": 9468, + "prompted": 9469, + "priority": 9470, + "forgot": 9471, + "bomber": 9472, + "nicolas": 9473, + "protective": 9474, + "360": 9475, + "cartoon": 9476, + "katherine": 9477, + "breeze": 9478, + "lonely": 9479, + "trusted": 9480, + "henderson": 9481, + "richardson": 9482, + "relax": 9483, + "banner": 9484, + "candy": 9485, + "palms": 9486, + "remarkable": 9487, + "##rio": 9488, + "legends": 9489, + "cricketer": 9490, + "essay": 9491, + "ordained": 9492, + "edmund": 9493, + "rifles": 9494, + "trigger": 9495, + "##uri": 9496, + "##away": 9497, + "sail": 9498, + "alert": 9499, + "1830": 9500, + "audiences": 9501, + "penn": 9502, + "sussex": 9503, + "siblings": 9504, + "pursued": 9505, + "indianapolis": 9506, + "resist": 9507, + "rosa": 9508, + "consequence": 9509, + "succeed": 9510, + "avoided": 9511, + "1845": 9512, + "##ulation": 9513, + "inland": 9514, + "##tie": 9515, + "##nna": 9516, + "counsel": 9517, + "profession": 9518, + "chronicle": 9519, + "hurried": 9520, + "##una": 9521, + "eyebrow": 9522, + "eventual": 9523, + "bleeding": 9524, + "innovative": 9525, + "cure": 9526, + "##dom": 9527, + "committees": 9528, + "accounting": 9529, + "con": 9530, + "scope": 9531, + "hardy": 9532, + "heather": 9533, + "tenor": 9534, + "gut": 9535, + "herald": 9536, + "codes": 9537, + "tore": 9538, + "scales": 9539, + "wagon": 9540, + "##oo": 9541, + "luxury": 9542, + "tin": 9543, + "prefer": 9544, + "fountain": 9545, + "triangle": 9546, + "bonds": 9547, + "darling": 9548, + "convoy": 9549, + "dried": 9550, + "traced": 9551, + "beings": 9552, + "troy": 9553, + "accidentally": 9554, + "slam": 9555, + "findings": 9556, + "smelled": 9557, + "joey": 9558, + "lawyers": 9559, + "outcome": 9560, + "steep": 9561, + "bosnia": 9562, + "configuration": 9563, + "shifting": 9564, + "toll": 9565, + "brook": 9566, + "performers": 9567, + "lobby": 9568, + "philosophical": 9569, + "construct": 9570, + "shrine": 9571, + "aggregate": 9572, + "boot": 9573, + "cox": 9574, + "phenomenon": 9575, + "savage": 9576, + "insane": 9577, + "solely": 9578, + "reynolds": 9579, + "lifestyle": 9580, + "##ima": 9581, + "nationally": 9582, + "holdings": 9583, + "consideration": 9584, + "enable": 9585, + "edgar": 9586, + "mo": 9587, + "mama": 9588, + "##tein": 9589, + "fights": 9590, + "relegation": 9591, + "chances": 9592, + "atomic": 9593, + "hub": 9594, + "conjunction": 9595, + "awkward": 9596, + "reactions": 9597, + "currency": 9598, + "finale": 9599, + "kumar": 9600, + "underwent": 9601, + "steering": 9602, + "elaborate": 9603, + "gifts": 9604, + "comprising": 9605, + "melissa": 9606, + "veins": 9607, + "reasonable": 9608, + "sunshine": 9609, + "chi": 9610, + "solve": 9611, + "trails": 9612, + "inhabited": 9613, + "elimination": 9614, + "ethics": 9615, + "huh": 9616, + "ana": 9617, + "molly": 9618, + "consent": 9619, + "apartments": 9620, + "layout": 9621, + "marines": 9622, + "##ces": 9623, + "hunters": 9624, + "bulk": 9625, + "##oma": 9626, + "hometown": 9627, + "##wall": 9628, + "##mont": 9629, + "cracked": 9630, + "reads": 9631, + "neighbouring": 9632, + "withdrawn": 9633, + "admission": 9634, + "wingspan": 9635, + "damned": 9636, + "anthology": 9637, + "lancashire": 9638, + "brands": 9639, + "batting": 9640, + "forgive": 9641, + "cuban": 9642, + "awful": 9643, + "##lyn": 9644, + "104": 9645, + "dimensions": 9646, + "imagination": 9647, + "##ade": 9648, + "dante": 9649, + "##ship": 9650, + "tracking": 9651, + "desperately": 9652, + "goalkeeper": 9653, + "##yne": 9654, + "groaned": 9655, + "workshops": 9656, + "confident": 9657, + "burton": 9658, + "gerald": 9659, + "milton": 9660, + "circus": 9661, + "uncertain": 9662, + "slope": 9663, + "copenhagen": 9664, + "sophia": 9665, + "fog": 9666, + "philosopher": 9667, + "portraits": 9668, + "accent": 9669, + "cycling": 9670, + "varying": 9671, + "gripped": 9672, + "larvae": 9673, + "garrett": 9674, + "specified": 9675, + "scotia": 9676, + "mature": 9677, + "luther": 9678, + "kurt": 9679, + "rap": 9680, + "##kes": 9681, + "aerial": 9682, + "750": 9683, + "ferdinand": 9684, + "heated": 9685, + "es": 9686, + "transported": 9687, + "##shan": 9688, + "safely": 9689, + "nonetheless": 9690, + "##orn": 9691, + "##gal": 9692, + "motors": 9693, + "demanding": 9694, + "##sburg": 9695, + "startled": 9696, + "##brook": 9697, + "ally": 9698, + "generate": 9699, + "caps": 9700, + "ghana": 9701, + "stained": 9702, + "demo": 9703, + "mentions": 9704, + "beds": 9705, + "ap": 9706, + "afterward": 9707, + "diary": 9708, + "##bling": 9709, + "utility": 9710, + "##iro": 9711, + "richards": 9712, + "1837": 9713, + "conspiracy": 9714, + "conscious": 9715, + "shining": 9716, + "footsteps": 9717, + "observer": 9718, + "cyprus": 9719, + "urged": 9720, + "loyalty": 9721, + "developer": 9722, + "probability": 9723, + "olive": 9724, + "upgraded": 9725, + "gym": 9726, + "miracle": 9727, + "insects": 9728, + "graves": 9729, + "1844": 9730, + "ourselves": 9731, + "hydrogen": 9732, + "amazon": 9733, + "katie": 9734, + "tickets": 9735, + "poets": 9736, + "##pm": 9737, + "planes": 9738, + "##pan": 9739, + "prevention": 9740, + "witnessed": 9741, + "dense": 9742, + "jin": 9743, + "randy": 9744, + "tang": 9745, + "warehouse": 9746, + "monroe": 9747, + "bang": 9748, + "archived": 9749, + "elderly": 9750, + "investigations": 9751, + "alec": 9752, + "granite": 9753, + "mineral": 9754, + "conflicts": 9755, + "controlling": 9756, + "aboriginal": 9757, + "carlo": 9758, + "##zu": 9759, + "mechanics": 9760, + "stan": 9761, + "stark": 9762, + "rhode": 9763, + "skirt": 9764, + "est": 9765, + "##berry": 9766, + "bombs": 9767, + "respected": 9768, + "##horn": 9769, + "imposed": 9770, + "limestone": 9771, + "deny": 9772, + "nominee": 9773, + "memphis": 9774, + "grabbing": 9775, + "disabled": 9776, + "##als": 9777, + "amusement": 9778, + "aa": 9779, + "frankfurt": 9780, + "corn": 9781, + "referendum": 9782, + "varies": 9783, + "slowed": 9784, + "disk": 9785, + "firms": 9786, + "unconscious": 9787, + "incredible": 9788, + "clue": 9789, + "sue": 9790, + "##zhou": 9791, + "twist": 9792, + "##cio": 9793, + "joins": 9794, + "idaho": 9795, + "chad": 9796, + "developers": 9797, + "computing": 9798, + "destroyer": 9799, + "103": 9800, + "mortal": 9801, + "tucker": 9802, + "kingston": 9803, + "choices": 9804, + "yu": 9805, + "carson": 9806, + "1800": 9807, + "os": 9808, + "whitney": 9809, + "geneva": 9810, + "pretend": 9811, + "dimension": 9812, + "staged": 9813, + "plateau": 9814, + "maya": 9815, + "##une": 9816, + "freestyle": 9817, + "##bc": 9818, + "rovers": 9819, + "hiv": 9820, + "##ids": 9821, + "tristan": 9822, + "classroom": 9823, + "prospect": 9824, + "##hus": 9825, + "honestly": 9826, + "diploma": 9827, + "lied": 9828, + "thermal": 9829, + "auxiliary": 9830, + "feast": 9831, + "unlikely": 9832, + "iata": 9833, + "##tel": 9834, + "morocco": 9835, + "pounding": 9836, + "treasury": 9837, + "lithuania": 9838, + "considerably": 9839, + "1841": 9840, + "dish": 9841, + "1812": 9842, + "geological": 9843, + "matching": 9844, + "stumbled": 9845, + "destroying": 9846, + "marched": 9847, + "brien": 9848, + "advances": 9849, + "cake": 9850, + "nicole": 9851, + "belle": 9852, + "settling": 9853, + "measuring": 9854, + "directing": 9855, + "##mie": 9856, + "tuesday": 9857, + "bassist": 9858, + "capabilities": 9859, + "stunned": 9860, + "fraud": 9861, + "torpedo": 9862, + "##list": 9863, + "##phone": 9864, + "anton": 9865, + "wisdom": 9866, + "surveillance": 9867, + "ruined": 9868, + "##ulate": 9869, + "lawsuit": 9870, + "healthcare": 9871, + "theorem": 9872, + "halls": 9873, + "trend": 9874, + "aka": 9875, + "horizontal": 9876, + "dozens": 9877, + "acquire": 9878, + "lasting": 9879, + "swim": 9880, + "hawk": 9881, + "gorgeous": 9882, + "fees": 9883, + "vicinity": 9884, + "decrease": 9885, + "adoption": 9886, + "tactics": 9887, + "##ography": 9888, + "pakistani": 9889, + "##ole": 9890, + "draws": 9891, + "##hall": 9892, + "willie": 9893, + "burke": 9894, + "heath": 9895, + "algorithm": 9896, + "integral": 9897, + "powder": 9898, + "elliott": 9899, + "brigadier": 9900, + "jackie": 9901, + "tate": 9902, + "varieties": 9903, + "darker": 9904, + "##cho": 9905, + "lately": 9906, + "cigarette": 9907, + "specimens": 9908, + "adds": 9909, + "##ree": 9910, + "##ensis": 9911, + "##inger": 9912, + "exploded": 9913, + "finalist": 9914, + "cia": 9915, + "murders": 9916, + "wilderness": 9917, + "arguments": 9918, + "nicknamed": 9919, + "acceptance": 9920, + "onwards": 9921, + "manufacture": 9922, + "robertson": 9923, + "jets": 9924, + "tampa": 9925, + "enterprises": 9926, + "blog": 9927, + "loudly": 9928, + "composers": 9929, + "nominations": 9930, + "1838": 9931, + "ai": 9932, + "malta": 9933, + "inquiry": 9934, + "automobile": 9935, + "hosting": 9936, + "viii": 9937, + "rays": 9938, + "tilted": 9939, + "grief": 9940, + "museums": 9941, + "strategies": 9942, + "furious": 9943, + "euro": 9944, + "equality": 9945, + "cohen": 9946, + "poison": 9947, + "surrey": 9948, + "wireless": 9949, + "governed": 9950, + "ridiculous": 9951, + "moses": 9952, + "##esh": 9953, + "##room": 9954, + "vanished": 9955, + "##ito": 9956, + "barnes": 9957, + "attract": 9958, + "morrison": 9959, + "istanbul": 9960, + "##iness": 9961, + "absent": 9962, + "rotation": 9963, + "petition": 9964, + "janet": 9965, + "##logical": 9966, + "satisfaction": 9967, + "custody": 9968, + "deliberately": 9969, + "observatory": 9970, + "comedian": 9971, + "surfaces": 9972, + "pinyin": 9973, + "novelist": 9974, + "strictly": 9975, + "canterbury": 9976, + "oslo": 9977, + "monks": 9978, + "embrace": 9979, + "ibm": 9980, + "jealous": 9981, + "photograph": 9982, + "continent": 9983, + "dorothy": 9984, + "marina": 9985, + "doc": 9986, + "excess": 9987, + "holden": 9988, + "allegations": 9989, + "explaining": 9990, + "stack": 9991, + "avoiding": 9992, + "lance": 9993, + "storyline": 9994, + "majesty": 9995, + "poorly": 9996, + "spike": 9997, + "dos": 9998, + "bradford": 9999, + "raven": 10000, + "travis": 10001, + "classics": 10002, + "proven": 10003, + "voltage": 10004, + "pillow": 10005, + "fists": 10006, + "butt": 10007, + "1842": 10008, + "interpreted": 10009, + "##car": 10010, + "1839": 10011, + "gage": 10012, + "telegraph": 10013, + "lens": 10014, + "promising": 10015, + "expelled": 10016, + "casual": 10017, + "collector": 10018, + "zones": 10019, + "##min": 10020, + "silly": 10021, + "nintendo": 10022, + "##kh": 10023, + "##bra": 10024, + "downstairs": 10025, + "chef": 10026, + "suspicious": 10027, + "afl": 10028, + "flies": 10029, + "vacant": 10030, + "uganda": 10031, + "pregnancy": 10032, + "condemned": 10033, + "lutheran": 10034, + "estimates": 10035, + "cheap": 10036, + "decree": 10037, + "saxon": 10038, + "proximity": 10039, + "stripped": 10040, + "idiot": 10041, + "deposits": 10042, + "contrary": 10043, + "presenter": 10044, + "magnus": 10045, + "glacier": 10046, + "im": 10047, + "offense": 10048, + "edwin": 10049, + "##ori": 10050, + "upright": 10051, + "##long": 10052, + "bolt": 10053, + "##ois": 10054, + "toss": 10055, + "geographical": 10056, + "##izes": 10057, + "environments": 10058, + "delicate": 10059, + "marking": 10060, + "abstract": 10061, + "xavier": 10062, + "nails": 10063, + "windsor": 10064, + "plantation": 10065, + "occurring": 10066, + "equity": 10067, + "saskatchewan": 10068, + "fears": 10069, + "drifted": 10070, + "sequences": 10071, + "vegetation": 10072, + "revolt": 10073, + "##stic": 10074, + "1843": 10075, + "sooner": 10076, + "fusion": 10077, + "opposing": 10078, + "nato": 10079, + "skating": 10080, + "1836": 10081, + "secretly": 10082, + "ruin": 10083, + "lease": 10084, + "##oc": 10085, + "edit": 10086, + "##nne": 10087, + "flora": 10088, + "anxiety": 10089, + "ruby": 10090, + "##ological": 10091, + "##mia": 10092, + "tel": 10093, + "bout": 10094, + "taxi": 10095, + "emmy": 10096, + "frost": 10097, + "rainbow": 10098, + "compounds": 10099, + "foundations": 10100, + "rainfall": 10101, + "assassination": 10102, + "nightmare": 10103, + "dominican": 10104, + "##win": 10105, + "achievements": 10106, + "deserve": 10107, + "orlando": 10108, + "intact": 10109, + "armenia": 10110, + "##nte": 10111, + "calgary": 10112, + "valentine": 10113, + "106": 10114, + "marion": 10115, + "proclaimed": 10116, + "theodore": 10117, + "bells": 10118, + "courtyard": 10119, + "thigh": 10120, + "gonzalez": 10121, + "console": 10122, + "troop": 10123, + "minimal": 10124, + "monte": 10125, + "everyday": 10126, + "##ence": 10127, + "##if": 10128, + "supporter": 10129, + "terrorism": 10130, + "buck": 10131, + "openly": 10132, + "presbyterian": 10133, + "activists": 10134, + "carpet": 10135, + "##iers": 10136, + "rubbing": 10137, + "uprising": 10138, + "##yi": 10139, + "cute": 10140, + "conceived": 10141, + "legally": 10142, + "##cht": 10143, + "millennium": 10144, + "cello": 10145, + "velocity": 10146, + "ji": 10147, + "rescued": 10148, + "cardiff": 10149, + "1835": 10150, + "rex": 10151, + "concentrate": 10152, + "senators": 10153, + "beard": 10154, + "rendered": 10155, + "glowing": 10156, + "battalions": 10157, + "scouts": 10158, + "competitors": 10159, + "sculptor": 10160, + "catalogue": 10161, + "arctic": 10162, + "ion": 10163, + "raja": 10164, + "bicycle": 10165, + "wow": 10166, + "glancing": 10167, + "lawn": 10168, + "##woman": 10169, + "gentleman": 10170, + "lighthouse": 10171, + "publish": 10172, + "predicted": 10173, + "calculated": 10174, + "##val": 10175, + "variants": 10176, + "##gne": 10177, + "strain": 10178, + "##ui": 10179, + "winston": 10180, + "deceased": 10181, + "##nus": 10182, + "touchdowns": 10183, + "brady": 10184, + "caleb": 10185, + "sinking": 10186, + "echoed": 10187, + "crush": 10188, + "hon": 10189, + "blessed": 10190, + "protagonist": 10191, + "hayes": 10192, + "endangered": 10193, + "magnitude": 10194, + "editors": 10195, + "##tine": 10196, + "estimate": 10197, + "responsibilities": 10198, + "##mel": 10199, + "backup": 10200, + "laying": 10201, + "consumed": 10202, + "sealed": 10203, + "zurich": 10204, + "lovers": 10205, + "frustrated": 10206, + "##eau": 10207, + "ahmed": 10208, + "kicking": 10209, + "mit": 10210, + "treasurer": 10211, + "1832": 10212, + "biblical": 10213, + "refuse": 10214, + "terrified": 10215, + "pump": 10216, + "agrees": 10217, + "genuine": 10218, + "imprisonment": 10219, + "refuses": 10220, + "plymouth": 10221, + "##hen": 10222, + "lou": 10223, + "##nen": 10224, + "tara": 10225, + "trembling": 10226, + "antarctic": 10227, + "ton": 10228, + "learns": 10229, + "##tas": 10230, + "crap": 10231, + "crucial": 10232, + "faction": 10233, + "atop": 10234, + "##borough": 10235, + "wrap": 10236, + "lancaster": 10237, + "odds": 10238, + "hopkins": 10239, + "erik": 10240, + "lyon": 10241, + "##eon": 10242, + "bros": 10243, + "##ode": 10244, + "snap": 10245, + "locality": 10246, + "tips": 10247, + "empress": 10248, + "crowned": 10249, + "cal": 10250, + "acclaimed": 10251, + "chuckled": 10252, + "##ory": 10253, + "clara": 10254, + "sends": 10255, + "mild": 10256, + "towel": 10257, + "##fl": 10258, + "##day": 10259, + "##а": 10260, + "wishing": 10261, + "assuming": 10262, + "interviewed": 10263, + "##bal": 10264, + "##die": 10265, + "interactions": 10266, + "eden": 10267, + "cups": 10268, + "helena": 10269, + "##lf": 10270, + "indie": 10271, + "beck": 10272, + "##fire": 10273, + "batteries": 10274, + "filipino": 10275, + "wizard": 10276, + "parted": 10277, + "##lam": 10278, + "traces": 10279, + "##born": 10280, + "rows": 10281, + "idol": 10282, + "albany": 10283, + "delegates": 10284, + "##ees": 10285, + "##sar": 10286, + "discussions": 10287, + "##ex": 10288, + "notre": 10289, + "instructed": 10290, + "belgrade": 10291, + "highways": 10292, + "suggestion": 10293, + "lauren": 10294, + "possess": 10295, + "orientation": 10296, + "alexandria": 10297, + "abdul": 10298, + "beats": 10299, + "salary": 10300, + "reunion": 10301, + "ludwig": 10302, + "alright": 10303, + "wagner": 10304, + "intimate": 10305, + "pockets": 10306, + "slovenia": 10307, + "hugged": 10308, + "brighton": 10309, + "merchants": 10310, + "cruel": 10311, + "stole": 10312, + "trek": 10313, + "slopes": 10314, + "repairs": 10315, + "enrollment": 10316, + "politically": 10317, + "underlying": 10318, + "promotional": 10319, + "counting": 10320, + "boeing": 10321, + "##bb": 10322, + "isabella": 10323, + "naming": 10324, + "##и": 10325, + "keen": 10326, + "bacteria": 10327, + "listing": 10328, + "separately": 10329, + "belfast": 10330, + "ussr": 10331, + "450": 10332, + "lithuanian": 10333, + "anybody": 10334, + "ribs": 10335, + "sphere": 10336, + "martinez": 10337, + "cock": 10338, + "embarrassed": 10339, + "proposals": 10340, + "fragments": 10341, + "nationals": 10342, + "##fs": 10343, + "##wski": 10344, + "premises": 10345, + "fin": 10346, + "1500": 10347, + "alpine": 10348, + "matched": 10349, + "freely": 10350, + "bounded": 10351, + "jace": 10352, + "sleeve": 10353, + "##af": 10354, + "gaming": 10355, + "pier": 10356, + "populated": 10357, + "evident": 10358, + "##like": 10359, + "frances": 10360, + "flooded": 10361, + "##dle": 10362, + "frightened": 10363, + "pour": 10364, + "trainer": 10365, + "framed": 10366, + "visitor": 10367, + "challenging": 10368, + "pig": 10369, + "wickets": 10370, + "##fold": 10371, + "infected": 10372, + "email": 10373, + "##pes": 10374, + "arose": 10375, + "##aw": 10376, + "reward": 10377, + "ecuador": 10378, + "oblast": 10379, + "vale": 10380, + "ch": 10381, + "shuttle": 10382, + "##usa": 10383, + "bach": 10384, + "rankings": 10385, + "forbidden": 10386, + "cornwall": 10387, + "accordance": 10388, + "salem": 10389, + "consumers": 10390, + "bruno": 10391, + "fantastic": 10392, + "toes": 10393, + "machinery": 10394, + "resolved": 10395, + "julius": 10396, + "remembering": 10397, + "propaganda": 10398, + "iceland": 10399, + "bombardment": 10400, + "tide": 10401, + "contacts": 10402, + "wives": 10403, + "##rah": 10404, + "concerto": 10405, + "macdonald": 10406, + "albania": 10407, + "implement": 10408, + "daisy": 10409, + "tapped": 10410, + "sudan": 10411, + "helmet": 10412, + "angela": 10413, + "mistress": 10414, + "##lic": 10415, + "crop": 10416, + "sunk": 10417, + "finest": 10418, + "##craft": 10419, + "hostile": 10420, + "##ute": 10421, + "##tsu": 10422, + "boxer": 10423, + "fr": 10424, + "paths": 10425, + "adjusted": 10426, + "habit": 10427, + "ballot": 10428, + "supervision": 10429, + "soprano": 10430, + "##zen": 10431, + "bullets": 10432, + "wicked": 10433, + "sunset": 10434, + "regiments": 10435, + "disappear": 10436, + "lamp": 10437, + "performs": 10438, + "app": 10439, + "##gia": 10440, + "##oa": 10441, + "rabbit": 10442, + "digging": 10443, + "incidents": 10444, + "entries": 10445, + "##cion": 10446, + "dishes": 10447, + "##oi": 10448, + "introducing": 10449, + "##ati": 10450, + "##fied": 10451, + "freshman": 10452, + "slot": 10453, + "jill": 10454, + "tackles": 10455, + "baroque": 10456, + "backs": 10457, + "##iest": 10458, + "lone": 10459, + "sponsor": 10460, + "destiny": 10461, + "altogether": 10462, + "convert": 10463, + "##aro": 10464, + "consensus": 10465, + "shapes": 10466, + "demonstration": 10467, + "basically": 10468, + "feminist": 10469, + "auction": 10470, + "artifacts": 10471, + "##bing": 10472, + "strongest": 10473, + "twitter": 10474, + "halifax": 10475, + "2019": 10476, + "allmusic": 10477, + "mighty": 10478, + "smallest": 10479, + "precise": 10480, + "alexandra": 10481, + "viola": 10482, + "##los": 10483, + "##ille": 10484, + "manuscripts": 10485, + "##illo": 10486, + "dancers": 10487, + "ari": 10488, + "managers": 10489, + "monuments": 10490, + "blades": 10491, + "barracks": 10492, + "springfield": 10493, + "maiden": 10494, + "consolidated": 10495, + "electron": 10496, + "##end": 10497, + "berry": 10498, + "airing": 10499, + "wheat": 10500, + "nobel": 10501, + "inclusion": 10502, + "blair": 10503, + "payments": 10504, + "geography": 10505, + "bee": 10506, + "cc": 10507, + "eleanor": 10508, + "react": 10509, + "##hurst": 10510, + "afc": 10511, + "manitoba": 10512, + "##yu": 10513, + "su": 10514, + "lineup": 10515, + "fitness": 10516, + "recreational": 10517, + "investments": 10518, + "airborne": 10519, + "disappointment": 10520, + "##dis": 10521, + "edmonton": 10522, + "viewing": 10523, + "##row": 10524, + "renovation": 10525, + "##cast": 10526, + "infant": 10527, + "bankruptcy": 10528, + "roses": 10529, + "aftermath": 10530, + "pavilion": 10531, + "##yer": 10532, + "carpenter": 10533, + "withdrawal": 10534, + "ladder": 10535, + "##hy": 10536, + "discussing": 10537, + "popped": 10538, + "reliable": 10539, + "agreements": 10540, + "rochester": 10541, + "##abad": 10542, + "curves": 10543, + "bombers": 10544, + "220": 10545, + "rao": 10546, + "reverend": 10547, + "decreased": 10548, + "choosing": 10549, + "107": 10550, + "stiff": 10551, + "consulting": 10552, + "naples": 10553, + "crawford": 10554, + "tracy": 10555, + "ka": 10556, + "ribbon": 10557, + "cops": 10558, + "##lee": 10559, + "crushed": 10560, + "deciding": 10561, + "unified": 10562, + "teenager": 10563, + "accepting": 10564, + "flagship": 10565, + "explorer": 10566, + "poles": 10567, + "sanchez": 10568, + "inspection": 10569, + "revived": 10570, + "skilled": 10571, + "induced": 10572, + "exchanged": 10573, + "flee": 10574, + "locals": 10575, + "tragedy": 10576, + "swallow": 10577, + "loading": 10578, + "hanna": 10579, + "demonstrate": 10580, + "##ela": 10581, + "salvador": 10582, + "flown": 10583, + "contestants": 10584, + "civilization": 10585, + "##ines": 10586, + "wanna": 10587, + "rhodes": 10588, + "fletcher": 10589, + "hector": 10590, + "knocking": 10591, + "considers": 10592, + "##ough": 10593, + "nash": 10594, + "mechanisms": 10595, + "sensed": 10596, + "mentally": 10597, + "walt": 10598, + "unclear": 10599, + "##eus": 10600, + "renovated": 10601, + "madame": 10602, + "##cks": 10603, + "crews": 10604, + "governmental": 10605, + "##hin": 10606, + "undertaken": 10607, + "monkey": 10608, + "##ben": 10609, + "##ato": 10610, + "fatal": 10611, + "armored": 10612, + "copa": 10613, + "caves": 10614, + "governance": 10615, + "grasp": 10616, + "perception": 10617, + "certification": 10618, + "froze": 10619, + "damp": 10620, + "tugged": 10621, + "wyoming": 10622, + "##rg": 10623, + "##ero": 10624, + "newman": 10625, + "##lor": 10626, + "nerves": 10627, + "curiosity": 10628, + "graph": 10629, + "115": 10630, + "##ami": 10631, + "withdraw": 10632, + "tunnels": 10633, + "dull": 10634, + "meredith": 10635, + "moss": 10636, + "exhibits": 10637, + "neighbors": 10638, + "communicate": 10639, + "accuracy": 10640, + "explored": 10641, + "raiders": 10642, + "republicans": 10643, + "secular": 10644, + "kat": 10645, + "superman": 10646, + "penny": 10647, + "criticised": 10648, + "##tch": 10649, + "freed": 10650, + "update": 10651, + "conviction": 10652, + "wade": 10653, + "ham": 10654, + "likewise": 10655, + "delegation": 10656, + "gotta": 10657, + "doll": 10658, + "promises": 10659, + "technological": 10660, + "myth": 10661, + "nationality": 10662, + "resolve": 10663, + "convent": 10664, + "##mark": 10665, + "sharon": 10666, + "dig": 10667, + "sip": 10668, + "coordinator": 10669, + "entrepreneur": 10670, + "fold": 10671, + "##dine": 10672, + "capability": 10673, + "councillor": 10674, + "synonym": 10675, + "blown": 10676, + "swan": 10677, + "cursed": 10678, + "1815": 10679, + "jonas": 10680, + "haired": 10681, + "sofa": 10682, + "canvas": 10683, + "keeper": 10684, + "rivalry": 10685, + "##hart": 10686, + "rapper": 10687, + "speedway": 10688, + "swords": 10689, + "postal": 10690, + "maxwell": 10691, + "estonia": 10692, + "potter": 10693, + "recurring": 10694, + "##nn": 10695, + "##ave": 10696, + "errors": 10697, + "##oni": 10698, + "cognitive": 10699, + "1834": 10700, + "##²": 10701, + "claws": 10702, + "nadu": 10703, + "roberto": 10704, + "bce": 10705, + "wrestler": 10706, + "ellie": 10707, + "##ations": 10708, + "infinite": 10709, + "ink": 10710, + "##tia": 10711, + "presumably": 10712, + "finite": 10713, + "staircase": 10714, + "108": 10715, + "noel": 10716, + "patricia": 10717, + "nacional": 10718, + "##cation": 10719, + "chill": 10720, + "eternal": 10721, + "tu": 10722, + "preventing": 10723, + "prussia": 10724, + "fossil": 10725, + "limbs": 10726, + "##logist": 10727, + "ernst": 10728, + "frog": 10729, + "perez": 10730, + "rene": 10731, + "##ace": 10732, + "pizza": 10733, + "prussian": 10734, + "##ios": 10735, + "##vy": 10736, + "molecules": 10737, + "regulatory": 10738, + "answering": 10739, + "opinions": 10740, + "sworn": 10741, + "lengths": 10742, + "supposedly": 10743, + "hypothesis": 10744, + "upward": 10745, + "habitats": 10746, + "seating": 10747, + "ancestors": 10748, + "drank": 10749, + "yield": 10750, + "hd": 10751, + "synthesis": 10752, + "researcher": 10753, + "modest": 10754, + "##var": 10755, + "mothers": 10756, + "peered": 10757, + "voluntary": 10758, + "homeland": 10759, + "##the": 10760, + "acclaim": 10761, + "##igan": 10762, + "static": 10763, + "valve": 10764, + "luxembourg": 10765, + "alto": 10766, + "carroll": 10767, + "fe": 10768, + "receptor": 10769, + "norton": 10770, + "ambulance": 10771, + "##tian": 10772, + "johnston": 10773, + "catholics": 10774, + "depicting": 10775, + "jointly": 10776, + "elephant": 10777, + "gloria": 10778, + "mentor": 10779, + "badge": 10780, + "ahmad": 10781, + "distinguish": 10782, + "remarked": 10783, + "councils": 10784, + "precisely": 10785, + "allison": 10786, + "advancing": 10787, + "detection": 10788, + "crowded": 10789, + "##10": 10790, + "cooperative": 10791, + "ankle": 10792, + "mercedes": 10793, + "dagger": 10794, + "surrendered": 10795, + "pollution": 10796, + "commit": 10797, + "subway": 10798, + "jeffrey": 10799, + "lesson": 10800, + "sculptures": 10801, + "provider": 10802, + "##fication": 10803, + "membrane": 10804, + "timothy": 10805, + "rectangular": 10806, + "fiscal": 10807, + "heating": 10808, + "teammate": 10809, + "basket": 10810, + "particle": 10811, + "anonymous": 10812, + "deployment": 10813, + "##ple": 10814, + "missiles": 10815, + "courthouse": 10816, + "proportion": 10817, + "shoe": 10818, + "sec": 10819, + "##ller": 10820, + "complaints": 10821, + "forbes": 10822, + "blacks": 10823, + "abandon": 10824, + "remind": 10825, + "sizes": 10826, + "overwhelming": 10827, + "autobiography": 10828, + "natalie": 10829, + "##awa": 10830, + "risks": 10831, + "contestant": 10832, + "countryside": 10833, + "babies": 10834, + "scorer": 10835, + "invaded": 10836, + "enclosed": 10837, + "proceed": 10838, + "hurling": 10839, + "disorders": 10840, + "##cu": 10841, + "reflecting": 10842, + "continuously": 10843, + "cruiser": 10844, + "graduates": 10845, + "freeway": 10846, + "investigated": 10847, + "ore": 10848, + "deserved": 10849, + "maid": 10850, + "blocking": 10851, + "phillip": 10852, + "jorge": 10853, + "shakes": 10854, + "dove": 10855, + "mann": 10856, + "variables": 10857, + "lacked": 10858, + "burden": 10859, + "accompanying": 10860, + "que": 10861, + "consistently": 10862, + "organizing": 10863, + "provisional": 10864, + "complained": 10865, + "endless": 10866, + "##rm": 10867, + "tubes": 10868, + "juice": 10869, + "georges": 10870, + "krishna": 10871, + "mick": 10872, + "labels": 10873, + "thriller": 10874, + "##uch": 10875, + "laps": 10876, + "arcade": 10877, + "sage": 10878, + "snail": 10879, + "##table": 10880, + "shannon": 10881, + "fi": 10882, + "laurence": 10883, + "seoul": 10884, + "vacation": 10885, + "presenting": 10886, + "hire": 10887, + "churchill": 10888, + "surprisingly": 10889, + "prohibited": 10890, + "savannah": 10891, + "technically": 10892, + "##oli": 10893, + "170": 10894, + "##lessly": 10895, + "testimony": 10896, + "suited": 10897, + "speeds": 10898, + "toys": 10899, + "romans": 10900, + "mlb": 10901, + "flowering": 10902, + "measurement": 10903, + "talented": 10904, + "kay": 10905, + "settings": 10906, + "charleston": 10907, + "expectations": 10908, + "shattered": 10909, + "achieving": 10910, + "triumph": 10911, + "ceremonies": 10912, + "portsmouth": 10913, + "lanes": 10914, + "mandatory": 10915, + "loser": 10916, + "stretching": 10917, + "cologne": 10918, + "realizes": 10919, + "seventy": 10920, + "cornell": 10921, + "careers": 10922, + "webb": 10923, + "##ulating": 10924, + "americas": 10925, + "budapest": 10926, + "ava": 10927, + "suspicion": 10928, + "##ison": 10929, + "yo": 10930, + "conrad": 10931, + "##hai": 10932, + "sterling": 10933, + "jessie": 10934, + "rector": 10935, + "##az": 10936, + "1831": 10937, + "transform": 10938, + "organize": 10939, + "loans": 10940, + "christine": 10941, + "volcanic": 10942, + "warrant": 10943, + "slender": 10944, + "summers": 10945, + "subfamily": 10946, + "newer": 10947, + "danced": 10948, + "dynamics": 10949, + "rhine": 10950, + "proceeds": 10951, + "heinrich": 10952, + "gastropod": 10953, + "commands": 10954, + "sings": 10955, + "facilitate": 10956, + "easter": 10957, + "ra": 10958, + "positioned": 10959, + "responses": 10960, + "expense": 10961, + "fruits": 10962, + "yanked": 10963, + "imported": 10964, + "25th": 10965, + "velvet": 10966, + "vic": 10967, + "primitive": 10968, + "tribune": 10969, + "baldwin": 10970, + "neighbourhood": 10971, + "donna": 10972, + "rip": 10973, + "hay": 10974, + "pr": 10975, + "##uro": 10976, + "1814": 10977, + "espn": 10978, + "welcomed": 10979, + "##aria": 10980, + "qualifier": 10981, + "glare": 10982, + "highland": 10983, + "timing": 10984, + "##cted": 10985, + "shells": 10986, + "eased": 10987, + "geometry": 10988, + "louder": 10989, + "exciting": 10990, + "slovakia": 10991, + "##sion": 10992, + "##iz": 10993, + "##lot": 10994, + "savings": 10995, + "prairie": 10996, + "##ques": 10997, + "marching": 10998, + "rafael": 10999, + "tonnes": 11000, + "##lled": 11001, + "curtain": 11002, + "preceding": 11003, + "shy": 11004, + "heal": 11005, + "greene": 11006, + "worthy": 11007, + "##pot": 11008, + "detachment": 11009, + "bury": 11010, + "sherman": 11011, + "##eck": 11012, + "reinforced": 11013, + "seeks": 11014, + "bottles": 11015, + "contracted": 11016, + "duchess": 11017, + "outfit": 11018, + "walsh": 11019, + "##sc": 11020, + "mickey": 11021, + "##ase": 11022, + "geoffrey": 11023, + "archer": 11024, + "squeeze": 11025, + "dawson": 11026, + "eliminate": 11027, + "invention": 11028, + "##enberg": 11029, + "neal": 11030, + "##eth": 11031, + "stance": 11032, + "dealer": 11033, + "coral": 11034, + "maple": 11035, + "retire": 11036, + "polo": 11037, + "simplified": 11038, + "##ht": 11039, + "1833": 11040, + "hid": 11041, + "watts": 11042, + "backwards": 11043, + "jules": 11044, + "##oke": 11045, + "genesis": 11046, + "mt": 11047, + "frames": 11048, + "rebounds": 11049, + "burma": 11050, + "woodland": 11051, + "moist": 11052, + "santos": 11053, + "whispers": 11054, + "drained": 11055, + "subspecies": 11056, + "##aa": 11057, + "streaming": 11058, + "ulster": 11059, + "burnt": 11060, + "correspondence": 11061, + "maternal": 11062, + "gerard": 11063, + "denis": 11064, + "stealing": 11065, + "##load": 11066, + "genius": 11067, + "duchy": 11068, + "##oria": 11069, + "inaugurated": 11070, + "momentum": 11071, + "suits": 11072, + "placement": 11073, + "sovereign": 11074, + "clause": 11075, + "thames": 11076, + "##hara": 11077, + "confederation": 11078, + "reservation": 11079, + "sketch": 11080, + "yankees": 11081, + "lets": 11082, + "rotten": 11083, + "charm": 11084, + "hal": 11085, + "verses": 11086, + "ultra": 11087, + "commercially": 11088, + "dot": 11089, + "salon": 11090, + "citation": 11091, + "adopt": 11092, + "winnipeg": 11093, + "mist": 11094, + "allocated": 11095, + "cairo": 11096, + "##boy": 11097, + "jenkins": 11098, + "interference": 11099, + "objectives": 11100, + "##wind": 11101, + "1820": 11102, + "portfolio": 11103, + "armoured": 11104, + "sectors": 11105, + "##eh": 11106, + "initiatives": 11107, + "##world": 11108, + "integrity": 11109, + "exercises": 11110, + "robe": 11111, + "tap": 11112, + "ab": 11113, + "gazed": 11114, + "##tones": 11115, + "distracted": 11116, + "rulers": 11117, + "111": 11118, + "favorable": 11119, + "jerome": 11120, + "tended": 11121, + "cart": 11122, + "factories": 11123, + "##eri": 11124, + "diplomat": 11125, + "valued": 11126, + "gravel": 11127, + "charitable": 11128, + "##try": 11129, + "calvin": 11130, + "exploring": 11131, + "chang": 11132, + "shepherd": 11133, + "terrace": 11134, + "pdf": 11135, + "pupil": 11136, + "##ural": 11137, + "reflects": 11138, + "ups": 11139, + "##rch": 11140, + "governors": 11141, + "shelf": 11142, + "depths": 11143, + "##nberg": 11144, + "trailed": 11145, + "crest": 11146, + "tackle": 11147, + "##nian": 11148, + "##ats": 11149, + "hatred": 11150, + "##kai": 11151, + "clare": 11152, + "makers": 11153, + "ethiopia": 11154, + "longtime": 11155, + "detected": 11156, + "embedded": 11157, + "lacking": 11158, + "slapped": 11159, + "rely": 11160, + "thomson": 11161, + "anticipation": 11162, + "iso": 11163, + "morton": 11164, + "successive": 11165, + "agnes": 11166, + "screenwriter": 11167, + "straightened": 11168, + "philippe": 11169, + "playwright": 11170, + "haunted": 11171, + "licence": 11172, + "iris": 11173, + "intentions": 11174, + "sutton": 11175, + "112": 11176, + "logical": 11177, + "correctly": 11178, + "##weight": 11179, + "branded": 11180, + "licked": 11181, + "tipped": 11182, + "silva": 11183, + "ricky": 11184, + "narrator": 11185, + "requests": 11186, + "##ents": 11187, + "greeted": 11188, + "supernatural": 11189, + "cow": 11190, + "##wald": 11191, + "lung": 11192, + "refusing": 11193, + "employer": 11194, + "strait": 11195, + "gaelic": 11196, + "liner": 11197, + "##piece": 11198, + "zoe": 11199, + "sabha": 11200, + "##mba": 11201, + "driveway": 11202, + "harvest": 11203, + "prints": 11204, + "bates": 11205, + "reluctantly": 11206, + "threshold": 11207, + "algebra": 11208, + "ira": 11209, + "wherever": 11210, + "coupled": 11211, + "240": 11212, + "assumption": 11213, + "picks": 11214, + "##air": 11215, + "designers": 11216, + "raids": 11217, + "gentlemen": 11218, + "##ean": 11219, + "roller": 11220, + "blowing": 11221, + "leipzig": 11222, + "locks": 11223, + "screw": 11224, + "dressing": 11225, + "strand": 11226, + "##lings": 11227, + "scar": 11228, + "dwarf": 11229, + "depicts": 11230, + "##nu": 11231, + "nods": 11232, + "##mine": 11233, + "differ": 11234, + "boris": 11235, + "##eur": 11236, + "yuan": 11237, + "flip": 11238, + "##gie": 11239, + "mob": 11240, + "invested": 11241, + "questioning": 11242, + "applying": 11243, + "##ture": 11244, + "shout": 11245, + "##sel": 11246, + "gameplay": 11247, + "blamed": 11248, + "illustrations": 11249, + "bothered": 11250, + "weakness": 11251, + "rehabilitation": 11252, + "##of": 11253, + "##zes": 11254, + "envelope": 11255, + "rumors": 11256, + "miners": 11257, + "leicester": 11258, + "subtle": 11259, + "kerry": 11260, + "##ico": 11261, + "ferguson": 11262, + "##fu": 11263, + "premiership": 11264, + "ne": 11265, + "##cat": 11266, + "bengali": 11267, + "prof": 11268, + "catches": 11269, + "remnants": 11270, + "dana": 11271, + "##rily": 11272, + "shouting": 11273, + "presidents": 11274, + "baltic": 11275, + "ought": 11276, + "ghosts": 11277, + "dances": 11278, + "sailors": 11279, + "shirley": 11280, + "fancy": 11281, + "dominic": 11282, + "##bie": 11283, + "madonna": 11284, + "##rick": 11285, + "bark": 11286, + "buttons": 11287, + "gymnasium": 11288, + "ashes": 11289, + "liver": 11290, + "toby": 11291, + "oath": 11292, + "providence": 11293, + "doyle": 11294, + "evangelical": 11295, + "nixon": 11296, + "cement": 11297, + "carnegie": 11298, + "embarked": 11299, + "hatch": 11300, + "surroundings": 11301, + "guarantee": 11302, + "needing": 11303, + "pirate": 11304, + "essence": 11305, + "##bee": 11306, + "filter": 11307, + "crane": 11308, + "hammond": 11309, + "projected": 11310, + "immune": 11311, + "percy": 11312, + "twelfth": 11313, + "##ult": 11314, + "regent": 11315, + "doctoral": 11316, + "damon": 11317, + "mikhail": 11318, + "##ichi": 11319, + "lu": 11320, + "critically": 11321, + "elect": 11322, + "realised": 11323, + "abortion": 11324, + "acute": 11325, + "screening": 11326, + "mythology": 11327, + "steadily": 11328, + "##fc": 11329, + "frown": 11330, + "nottingham": 11331, + "kirk": 11332, + "wa": 11333, + "minneapolis": 11334, + "##rra": 11335, + "module": 11336, + "algeria": 11337, + "mc": 11338, + "nautical": 11339, + "encounters": 11340, + "surprising": 11341, + "statues": 11342, + "availability": 11343, + "shirts": 11344, + "pie": 11345, + "alma": 11346, + "brows": 11347, + "munster": 11348, + "mack": 11349, + "soup": 11350, + "crater": 11351, + "tornado": 11352, + "sanskrit": 11353, + "cedar": 11354, + "explosive": 11355, + "bordered": 11356, + "dixon": 11357, + "planets": 11358, + "stamp": 11359, + "exam": 11360, + "happily": 11361, + "##bble": 11362, + "carriers": 11363, + "kidnapped": 11364, + "##vis": 11365, + "accommodation": 11366, + "emigrated": 11367, + "##met": 11368, + "knockout": 11369, + "correspondent": 11370, + "violation": 11371, + "profits": 11372, + "peaks": 11373, + "lang": 11374, + "specimen": 11375, + "agenda": 11376, + "ancestry": 11377, + "pottery": 11378, + "spelling": 11379, + "equations": 11380, + "obtaining": 11381, + "ki": 11382, + "linking": 11383, + "1825": 11384, + "debris": 11385, + "asylum": 11386, + "##20": 11387, + "buddhism": 11388, + "teddy": 11389, + "##ants": 11390, + "gazette": 11391, + "##nger": 11392, + "##sse": 11393, + "dental": 11394, + "eligibility": 11395, + "utc": 11396, + "fathers": 11397, + "averaged": 11398, + "zimbabwe": 11399, + "francesco": 11400, + "coloured": 11401, + "hissed": 11402, + "translator": 11403, + "lynch": 11404, + "mandate": 11405, + "humanities": 11406, + "mackenzie": 11407, + "uniforms": 11408, + "lin": 11409, + "##iana": 11410, + "##gio": 11411, + "asset": 11412, + "mhz": 11413, + "fitting": 11414, + "samantha": 11415, + "genera": 11416, + "wei": 11417, + "rim": 11418, + "beloved": 11419, + "shark": 11420, + "riot": 11421, + "entities": 11422, + "expressions": 11423, + "indo": 11424, + "carmen": 11425, + "slipping": 11426, + "owing": 11427, + "abbot": 11428, + "neighbor": 11429, + "sidney": 11430, + "##av": 11431, + "rats": 11432, + "recommendations": 11433, + "encouraging": 11434, + "squadrons": 11435, + "anticipated": 11436, + "commanders": 11437, + "conquered": 11438, + "##oto": 11439, + "donations": 11440, + "diagnosed": 11441, + "##mond": 11442, + "divide": 11443, + "##iva": 11444, + "guessed": 11445, + "decoration": 11446, + "vernon": 11447, + "auditorium": 11448, + "revelation": 11449, + "conversations": 11450, + "##kers": 11451, + "##power": 11452, + "herzegovina": 11453, + "dash": 11454, + "alike": 11455, + "protested": 11456, + "lateral": 11457, + "herman": 11458, + "accredited": 11459, + "mg": 11460, + "##gent": 11461, + "freeman": 11462, + "mel": 11463, + "fiji": 11464, + "crow": 11465, + "crimson": 11466, + "##rine": 11467, + "livestock": 11468, + "##pped": 11469, + "humanitarian": 11470, + "bored": 11471, + "oz": 11472, + "whip": 11473, + "##lene": 11474, + "##ali": 11475, + "legitimate": 11476, + "alter": 11477, + "grinning": 11478, + "spelled": 11479, + "anxious": 11480, + "oriental": 11481, + "wesley": 11482, + "##nin": 11483, + "##hole": 11484, + "carnival": 11485, + "controller": 11486, + "detect": 11487, + "##ssa": 11488, + "bowed": 11489, + "educator": 11490, + "kosovo": 11491, + "macedonia": 11492, + "##sin": 11493, + "occupy": 11494, + "mastering": 11495, + "stephanie": 11496, + "janeiro": 11497, + "para": 11498, + "unaware": 11499, + "nurses": 11500, + "noon": 11501, + "135": 11502, + "cam": 11503, + "hopefully": 11504, + "ranger": 11505, + "combine": 11506, + "sociology": 11507, + "polar": 11508, + "rica": 11509, + "##eer": 11510, + "neill": 11511, + "##sman": 11512, + "holocaust": 11513, + "##ip": 11514, + "doubled": 11515, + "lust": 11516, + "1828": 11517, + "109": 11518, + "decent": 11519, + "cooling": 11520, + "unveiled": 11521, + "##card": 11522, + "1829": 11523, + "nsw": 11524, + "homer": 11525, + "chapman": 11526, + "meyer": 11527, + "##gin": 11528, + "dive": 11529, + "mae": 11530, + "reagan": 11531, + "expertise": 11532, + "##gled": 11533, + "darwin": 11534, + "brooke": 11535, + "sided": 11536, + "prosecution": 11537, + "investigating": 11538, + "comprised": 11539, + "petroleum": 11540, + "genres": 11541, + "reluctant": 11542, + "differently": 11543, + "trilogy": 11544, + "johns": 11545, + "vegetables": 11546, + "corpse": 11547, + "highlighted": 11548, + "lounge": 11549, + "pension": 11550, + "unsuccessfully": 11551, + "elegant": 11552, + "aided": 11553, + "ivory": 11554, + "beatles": 11555, + "amelia": 11556, + "cain": 11557, + "dubai": 11558, + "sunny": 11559, + "immigrant": 11560, + "babe": 11561, + "click": 11562, + "##nder": 11563, + "underwater": 11564, + "pepper": 11565, + "combining": 11566, + "mumbled": 11567, + "atlas": 11568, + "horns": 11569, + "accessed": 11570, + "ballad": 11571, + "physicians": 11572, + "homeless": 11573, + "gestured": 11574, + "rpm": 11575, + "freak": 11576, + "louisville": 11577, + "corporations": 11578, + "patriots": 11579, + "prizes": 11580, + "rational": 11581, + "warn": 11582, + "modes": 11583, + "decorative": 11584, + "overnight": 11585, + "din": 11586, + "troubled": 11587, + "phantom": 11588, + "##ort": 11589, + "monarch": 11590, + "sheer": 11591, + "##dorf": 11592, + "generals": 11593, + "guidelines": 11594, + "organs": 11595, + "addresses": 11596, + "##zon": 11597, + "enhance": 11598, + "curling": 11599, + "parishes": 11600, + "cord": 11601, + "##kie": 11602, + "linux": 11603, + "caesar": 11604, + "deutsche": 11605, + "bavaria": 11606, + "##bia": 11607, + "coleman": 11608, + "cyclone": 11609, + "##eria": 11610, + "bacon": 11611, + "petty": 11612, + "##yama": 11613, + "##old": 11614, + "hampton": 11615, + "diagnosis": 11616, + "1824": 11617, + "throws": 11618, + "complexity": 11619, + "rita": 11620, + "disputed": 11621, + "##₃": 11622, + "pablo": 11623, + "##sch": 11624, + "marketed": 11625, + "trafficking": 11626, + "##ulus": 11627, + "examine": 11628, + "plague": 11629, + "formats": 11630, + "##oh": 11631, + "vault": 11632, + "faithful": 11633, + "##bourne": 11634, + "webster": 11635, + "##ox": 11636, + "highlights": 11637, + "##ient": 11638, + "##ann": 11639, + "phones": 11640, + "vacuum": 11641, + "sandwich": 11642, + "modeling": 11643, + "##gated": 11644, + "bolivia": 11645, + "clergy": 11646, + "qualities": 11647, + "isabel": 11648, + "##nas": 11649, + "##ars": 11650, + "wears": 11651, + "screams": 11652, + "reunited": 11653, + "annoyed": 11654, + "bra": 11655, + "##ancy": 11656, + "##rate": 11657, + "differential": 11658, + "transmitter": 11659, + "tattoo": 11660, + "container": 11661, + "poker": 11662, + "##och": 11663, + "excessive": 11664, + "resides": 11665, + "cowboys": 11666, + "##tum": 11667, + "augustus": 11668, + "trash": 11669, + "providers": 11670, + "statute": 11671, + "retreated": 11672, + "balcony": 11673, + "reversed": 11674, + "void": 11675, + "storey": 11676, + "preceded": 11677, + "masses": 11678, + "leap": 11679, + "laughs": 11680, + "neighborhoods": 11681, + "wards": 11682, + "schemes": 11683, + "falcon": 11684, + "santo": 11685, + "battlefield": 11686, + "pad": 11687, + "ronnie": 11688, + "thread": 11689, + "lesbian": 11690, + "venus": 11691, + "##dian": 11692, + "beg": 11693, + "sandstone": 11694, + "daylight": 11695, + "punched": 11696, + "gwen": 11697, + "analog": 11698, + "stroked": 11699, + "wwe": 11700, + "acceptable": 11701, + "measurements": 11702, + "dec": 11703, + "toxic": 11704, + "##kel": 11705, + "adequate": 11706, + "surgical": 11707, + "economist": 11708, + "parameters": 11709, + "varsity": 11710, + "##sberg": 11711, + "quantity": 11712, + "ella": 11713, + "##chy": 11714, + "##rton": 11715, + "countess": 11716, + "generating": 11717, + "precision": 11718, + "diamonds": 11719, + "expressway": 11720, + "ga": 11721, + "##ı": 11722, + "1821": 11723, + "uruguay": 11724, + "talents": 11725, + "galleries": 11726, + "expenses": 11727, + "scanned": 11728, + "colleague": 11729, + "outlets": 11730, + "ryder": 11731, + "lucien": 11732, + "##ila": 11733, + "paramount": 11734, + "##bon": 11735, + "syracuse": 11736, + "dim": 11737, + "fangs": 11738, + "gown": 11739, + "sweep": 11740, + "##sie": 11741, + "toyota": 11742, + "missionaries": 11743, + "websites": 11744, + "##nsis": 11745, + "sentences": 11746, + "adviser": 11747, + "val": 11748, + "trademark": 11749, + "spells": 11750, + "##plane": 11751, + "patience": 11752, + "starter": 11753, + "slim": 11754, + "##borg": 11755, + "toe": 11756, + "incredibly": 11757, + "shoots": 11758, + "elliot": 11759, + "nobility": 11760, + "##wyn": 11761, + "cowboy": 11762, + "endorsed": 11763, + "gardner": 11764, + "tendency": 11765, + "persuaded": 11766, + "organisms": 11767, + "emissions": 11768, + "kazakhstan": 11769, + "amused": 11770, + "boring": 11771, + "chips": 11772, + "themed": 11773, + "##hand": 11774, + "llc": 11775, + "constantinople": 11776, + "chasing": 11777, + "systematic": 11778, + "guatemala": 11779, + "borrowed": 11780, + "erin": 11781, + "carey": 11782, + "##hard": 11783, + "highlands": 11784, + "struggles": 11785, + "1810": 11786, + "##ifying": 11787, + "##ced": 11788, + "wong": 11789, + "exceptions": 11790, + "develops": 11791, + "enlarged": 11792, + "kindergarten": 11793, + "castro": 11794, + "##ern": 11795, + "##rina": 11796, + "leigh": 11797, + "zombie": 11798, + "juvenile": 11799, + "##most": 11800, + "consul": 11801, + "##nar": 11802, + "sailor": 11803, + "hyde": 11804, + "clarence": 11805, + "intensive": 11806, + "pinned": 11807, + "nasty": 11808, + "useless": 11809, + "jung": 11810, + "clayton": 11811, + "stuffed": 11812, + "exceptional": 11813, + "ix": 11814, + "apostolic": 11815, + "230": 11816, + "transactions": 11817, + "##dge": 11818, + "exempt": 11819, + "swinging": 11820, + "cove": 11821, + "religions": 11822, + "##ash": 11823, + "shields": 11824, + "dairy": 11825, + "bypass": 11826, + "190": 11827, + "pursuing": 11828, + "bug": 11829, + "joyce": 11830, + "bombay": 11831, + "chassis": 11832, + "southampton": 11833, + "chat": 11834, + "interact": 11835, + "redesignated": 11836, + "##pen": 11837, + "nascar": 11838, + "pray": 11839, + "salmon": 11840, + "rigid": 11841, + "regained": 11842, + "malaysian": 11843, + "grim": 11844, + "publicity": 11845, + "constituted": 11846, + "capturing": 11847, + "toilet": 11848, + "delegate": 11849, + "purely": 11850, + "tray": 11851, + "drift": 11852, + "loosely": 11853, + "striker": 11854, + "weakened": 11855, + "trinidad": 11856, + "mitch": 11857, + "itv": 11858, + "defines": 11859, + "transmitted": 11860, + "ming": 11861, + "scarlet": 11862, + "nodding": 11863, + "fitzgerald": 11864, + "fu": 11865, + "narrowly": 11866, + "sp": 11867, + "tooth": 11868, + "standings": 11869, + "virtue": 11870, + "##₁": 11871, + "##wara": 11872, + "##cting": 11873, + "chateau": 11874, + "gloves": 11875, + "lid": 11876, + "##nel": 11877, + "hurting": 11878, + "conservatory": 11879, + "##pel": 11880, + "sinclair": 11881, + "reopened": 11882, + "sympathy": 11883, + "nigerian": 11884, + "strode": 11885, + "advocated": 11886, + "optional": 11887, + "chronic": 11888, + "discharge": 11889, + "##rc": 11890, + "suck": 11891, + "compatible": 11892, + "laurel": 11893, + "stella": 11894, + "shi": 11895, + "fails": 11896, + "wage": 11897, + "dodge": 11898, + "128": 11899, + "informal": 11900, + "sorts": 11901, + "levi": 11902, + "buddha": 11903, + "villagers": 11904, + "##aka": 11905, + "chronicles": 11906, + "heavier": 11907, + "summoned": 11908, + "gateway": 11909, + "3000": 11910, + "eleventh": 11911, + "jewelry": 11912, + "translations": 11913, + "accordingly": 11914, + "seas": 11915, + "##ency": 11916, + "fiber": 11917, + "pyramid": 11918, + "cubic": 11919, + "dragging": 11920, + "##ista": 11921, + "caring": 11922, + "##ops": 11923, + "android": 11924, + "contacted": 11925, + "lunar": 11926, + "##dt": 11927, + "kai": 11928, + "lisbon": 11929, + "patted": 11930, + "1826": 11931, + "sacramento": 11932, + "theft": 11933, + "madagascar": 11934, + "subtropical": 11935, + "disputes": 11936, + "ta": 11937, + "holidays": 11938, + "piper": 11939, + "willow": 11940, + "mare": 11941, + "cane": 11942, + "itunes": 11943, + "newfoundland": 11944, + "benny": 11945, + "companions": 11946, + "dong": 11947, + "raj": 11948, + "observe": 11949, + "roar": 11950, + "charming": 11951, + "plaque": 11952, + "tibetan": 11953, + "fossils": 11954, + "enacted": 11955, + "manning": 11956, + "bubble": 11957, + "tina": 11958, + "tanzania": 11959, + "##eda": 11960, + "##hir": 11961, + "funk": 11962, + "swamp": 11963, + "deputies": 11964, + "cloak": 11965, + "ufc": 11966, + "scenario": 11967, + "par": 11968, + "scratch": 11969, + "metals": 11970, + "anthem": 11971, + "guru": 11972, + "engaging": 11973, + "specially": 11974, + "##boat": 11975, + "dialects": 11976, + "nineteen": 11977, + "cecil": 11978, + "duet": 11979, + "disability": 11980, + "messenger": 11981, + "unofficial": 11982, + "##lies": 11983, + "defunct": 11984, + "eds": 11985, + "moonlight": 11986, + "drainage": 11987, + "surname": 11988, + "puzzle": 11989, + "honda": 11990, + "switching": 11991, + "conservatives": 11992, + "mammals": 11993, + "knox": 11994, + "broadcaster": 11995, + "sidewalk": 11996, + "cope": 11997, + "##ried": 11998, + "benson": 11999, + "princes": 12000, + "peterson": 12001, + "##sal": 12002, + "bedford": 12003, + "sharks": 12004, + "eli": 12005, + "wreck": 12006, + "alberto": 12007, + "gasp": 12008, + "archaeology": 12009, + "lgbt": 12010, + "teaches": 12011, + "securities": 12012, + "madness": 12013, + "compromise": 12014, + "waving": 12015, + "coordination": 12016, + "davidson": 12017, + "visions": 12018, + "leased": 12019, + "possibilities": 12020, + "eighty": 12021, + "jun": 12022, + "fernandez": 12023, + "enthusiasm": 12024, + "assassin": 12025, + "sponsorship": 12026, + "reviewer": 12027, + "kingdoms": 12028, + "estonian": 12029, + "laboratories": 12030, + "##fy": 12031, + "##nal": 12032, + "applies": 12033, + "verb": 12034, + "celebrations": 12035, + "##zzo": 12036, + "rowing": 12037, + "lightweight": 12038, + "sadness": 12039, + "submit": 12040, + "mvp": 12041, + "balanced": 12042, + "dude": 12043, + "##vas": 12044, + "explicitly": 12045, + "metric": 12046, + "magnificent": 12047, + "mound": 12048, + "brett": 12049, + "mohammad": 12050, + "mistakes": 12051, + "irregular": 12052, + "##hing": 12053, + "##ass": 12054, + "sanders": 12055, + "betrayed": 12056, + "shipped": 12057, + "surge": 12058, + "##enburg": 12059, + "reporters": 12060, + "termed": 12061, + "georg": 12062, + "pity": 12063, + "verbal": 12064, + "bulls": 12065, + "abbreviated": 12066, + "enabling": 12067, + "appealed": 12068, + "##are": 12069, + "##atic": 12070, + "sicily": 12071, + "sting": 12072, + "heel": 12073, + "sweetheart": 12074, + "bart": 12075, + "spacecraft": 12076, + "brutal": 12077, + "monarchy": 12078, + "##tter": 12079, + "aberdeen": 12080, + "cameo": 12081, + "diane": 12082, + "##ub": 12083, + "survivor": 12084, + "clyde": 12085, + "##aries": 12086, + "complaint": 12087, + "##makers": 12088, + "clarinet": 12089, + "delicious": 12090, + "chilean": 12091, + "karnataka": 12092, + "coordinates": 12093, + "1818": 12094, + "panties": 12095, + "##rst": 12096, + "pretending": 12097, + "ar": 12098, + "dramatically": 12099, + "kiev": 12100, + "bella": 12101, + "tends": 12102, + "distances": 12103, + "113": 12104, + "catalog": 12105, + "launching": 12106, + "instances": 12107, + "telecommunications": 12108, + "portable": 12109, + "lindsay": 12110, + "vatican": 12111, + "##eim": 12112, + "angles": 12113, + "aliens": 12114, + "marker": 12115, + "stint": 12116, + "screens": 12117, + "bolton": 12118, + "##rne": 12119, + "judy": 12120, + "wool": 12121, + "benedict": 12122, + "plasma": 12123, + "europa": 12124, + "spark": 12125, + "imaging": 12126, + "filmmaker": 12127, + "swiftly": 12128, + "##een": 12129, + "contributor": 12130, + "##nor": 12131, + "opted": 12132, + "stamps": 12133, + "apologize": 12134, + "financing": 12135, + "butter": 12136, + "gideon": 12137, + "sophisticated": 12138, + "alignment": 12139, + "avery": 12140, + "chemicals": 12141, + "yearly": 12142, + "speculation": 12143, + "prominence": 12144, + "professionally": 12145, + "##ils": 12146, + "immortal": 12147, + "institutional": 12148, + "inception": 12149, + "wrists": 12150, + "identifying": 12151, + "tribunal": 12152, + "derives": 12153, + "gains": 12154, + "##wo": 12155, + "papal": 12156, + "preference": 12157, + "linguistic": 12158, + "vince": 12159, + "operative": 12160, + "brewery": 12161, + "##ont": 12162, + "unemployment": 12163, + "boyd": 12164, + "##ured": 12165, + "##outs": 12166, + "albeit": 12167, + "prophet": 12168, + "1813": 12169, + "bi": 12170, + "##rr": 12171, + "##face": 12172, + "##rad": 12173, + "quarterly": 12174, + "asteroid": 12175, + "cleaned": 12176, + "radius": 12177, + "temper": 12178, + "##llen": 12179, + "telugu": 12180, + "jerk": 12181, + "viscount": 12182, + "menu": 12183, + "##ote": 12184, + "glimpse": 12185, + "##aya": 12186, + "yacht": 12187, + "hawaiian": 12188, + "baden": 12189, + "##rl": 12190, + "laptop": 12191, + "readily": 12192, + "##gu": 12193, + "monetary": 12194, + "offshore": 12195, + "scots": 12196, + "watches": 12197, + "##yang": 12198, + "##arian": 12199, + "upgrade": 12200, + "needle": 12201, + "xbox": 12202, + "lea": 12203, + "encyclopedia": 12204, + "flank": 12205, + "fingertips": 12206, + "##pus": 12207, + "delight": 12208, + "teachings": 12209, + "confirm": 12210, + "roth": 12211, + "beaches": 12212, + "midway": 12213, + "winters": 12214, + "##iah": 12215, + "teasing": 12216, + "daytime": 12217, + "beverly": 12218, + "gambling": 12219, + "bonnie": 12220, + "##backs": 12221, + "regulated": 12222, + "clement": 12223, + "hermann": 12224, + "tricks": 12225, + "knot": 12226, + "##shing": 12227, + "##uring": 12228, + "##vre": 12229, + "detached": 12230, + "ecological": 12231, + "owed": 12232, + "specialty": 12233, + "byron": 12234, + "inventor": 12235, + "bats": 12236, + "stays": 12237, + "screened": 12238, + "unesco": 12239, + "midland": 12240, + "trim": 12241, + "affection": 12242, + "##ander": 12243, + "##rry": 12244, + "jess": 12245, + "thoroughly": 12246, + "feedback": 12247, + "##uma": 12248, + "chennai": 12249, + "strained": 12250, + "heartbeat": 12251, + "wrapping": 12252, + "overtime": 12253, + "pleaded": 12254, + "##sworth": 12255, + "mon": 12256, + "leisure": 12257, + "oclc": 12258, + "##tate": 12259, + "##ele": 12260, + "feathers": 12261, + "angelo": 12262, + "thirds": 12263, + "nuts": 12264, + "surveys": 12265, + "clever": 12266, + "gill": 12267, + "commentator": 12268, + "##dos": 12269, + "darren": 12270, + "rides": 12271, + "gibraltar": 12272, + "##nc": 12273, + "##mu": 12274, + "dissolution": 12275, + "dedication": 12276, + "shin": 12277, + "meals": 12278, + "saddle": 12279, + "elvis": 12280, + "reds": 12281, + "chaired": 12282, + "taller": 12283, + "appreciation": 12284, + "functioning": 12285, + "niece": 12286, + "favored": 12287, + "advocacy": 12288, + "robbie": 12289, + "criminals": 12290, + "suffolk": 12291, + "yugoslav": 12292, + "passport": 12293, + "constable": 12294, + "congressman": 12295, + "hastings": 12296, + "vera": 12297, + "##rov": 12298, + "consecrated": 12299, + "sparks": 12300, + "ecclesiastical": 12301, + "confined": 12302, + "##ovich": 12303, + "muller": 12304, + "floyd": 12305, + "nora": 12306, + "1822": 12307, + "paved": 12308, + "1827": 12309, + "cumberland": 12310, + "ned": 12311, + "saga": 12312, + "spiral": 12313, + "##flow": 12314, + "appreciated": 12315, + "yi": 12316, + "collaborative": 12317, + "treating": 12318, + "similarities": 12319, + "feminine": 12320, + "finishes": 12321, + "##ib": 12322, + "jade": 12323, + "import": 12324, + "##nse": 12325, + "##hot": 12326, + "champagne": 12327, + "mice": 12328, + "securing": 12329, + "celebrities": 12330, + "helsinki": 12331, + "attributes": 12332, + "##gos": 12333, + "cousins": 12334, + "phases": 12335, + "ache": 12336, + "lucia": 12337, + "gandhi": 12338, + "submission": 12339, + "vicar": 12340, + "spear": 12341, + "shine": 12342, + "tasmania": 12343, + "biting": 12344, + "detention": 12345, + "constitute": 12346, + "tighter": 12347, + "seasonal": 12348, + "##gus": 12349, + "terrestrial": 12350, + "matthews": 12351, + "##oka": 12352, + "effectiveness": 12353, + "parody": 12354, + "philharmonic": 12355, + "##onic": 12356, + "1816": 12357, + "strangers": 12358, + "encoded": 12359, + "consortium": 12360, + "guaranteed": 12361, + "regards": 12362, + "shifts": 12363, + "tortured": 12364, + "collision": 12365, + "supervisor": 12366, + "inform": 12367, + "broader": 12368, + "insight": 12369, + "theaters": 12370, + "armour": 12371, + "emeritus": 12372, + "blink": 12373, + "incorporates": 12374, + "mapping": 12375, + "##50": 12376, + "##ein": 12377, + "handball": 12378, + "flexible": 12379, + "##nta": 12380, + "substantially": 12381, + "generous": 12382, + "thief": 12383, + "##own": 12384, + "carr": 12385, + "loses": 12386, + "1793": 12387, + "prose": 12388, + "ucla": 12389, + "romeo": 12390, + "generic": 12391, + "metallic": 12392, + "realization": 12393, + "damages": 12394, + "mk": 12395, + "commissioners": 12396, + "zach": 12397, + "default": 12398, + "##ther": 12399, + "helicopters": 12400, + "lengthy": 12401, + "stems": 12402, + "spa": 12403, + "partnered": 12404, + "spectators": 12405, + "rogue": 12406, + "indication": 12407, + "penalties": 12408, + "teresa": 12409, + "1801": 12410, + "sen": 12411, + "##tric": 12412, + "dalton": 12413, + "##wich": 12414, + "irving": 12415, + "photographic": 12416, + "##vey": 12417, + "dell": 12418, + "deaf": 12419, + "peters": 12420, + "excluded": 12421, + "unsure": 12422, + "##vable": 12423, + "patterson": 12424, + "crawled": 12425, + "##zio": 12426, + "resided": 12427, + "whipped": 12428, + "latvia": 12429, + "slower": 12430, + "ecole": 12431, + "pipes": 12432, + "employers": 12433, + "maharashtra": 12434, + "comparable": 12435, + "va": 12436, + "textile": 12437, + "pageant": 12438, + "##gel": 12439, + "alphabet": 12440, + "binary": 12441, + "irrigation": 12442, + "chartered": 12443, + "choked": 12444, + "antoine": 12445, + "offs": 12446, + "waking": 12447, + "supplement": 12448, + "##wen": 12449, + "quantities": 12450, + "demolition": 12451, + "regain": 12452, + "locate": 12453, + "urdu": 12454, + "folks": 12455, + "alt": 12456, + "114": 12457, + "##mc": 12458, + "scary": 12459, + "andreas": 12460, + "whites": 12461, + "##ava": 12462, + "classrooms": 12463, + "mw": 12464, + "aesthetic": 12465, + "publishes": 12466, + "valleys": 12467, + "guides": 12468, + "cubs": 12469, + "johannes": 12470, + "bryant": 12471, + "conventions": 12472, + "affecting": 12473, + "##itt": 12474, + "drain": 12475, + "awesome": 12476, + "isolation": 12477, + "prosecutor": 12478, + "ambitious": 12479, + "apology": 12480, + "captive": 12481, + "downs": 12482, + "atmospheric": 12483, + "lorenzo": 12484, + "aisle": 12485, + "beef": 12486, + "foul": 12487, + "##onia": 12488, + "kidding": 12489, + "composite": 12490, + "disturbed": 12491, + "illusion": 12492, + "natives": 12493, + "##ffer": 12494, + "emi": 12495, + "rockets": 12496, + "riverside": 12497, + "wartime": 12498, + "painters": 12499, + "adolf": 12500, + "melted": 12501, + "##ail": 12502, + "uncertainty": 12503, + "simulation": 12504, + "hawks": 12505, + "progressed": 12506, + "meantime": 12507, + "builder": 12508, + "spray": 12509, + "breach": 12510, + "unhappy": 12511, + "regina": 12512, + "russians": 12513, + "##urg": 12514, + "determining": 12515, + "##tation": 12516, + "tram": 12517, + "1806": 12518, + "##quin": 12519, + "aging": 12520, + "##12": 12521, + "1823": 12522, + "garion": 12523, + "rented": 12524, + "mister": 12525, + "diaz": 12526, + "terminated": 12527, + "clip": 12528, + "1817": 12529, + "depend": 12530, + "nervously": 12531, + "disco": 12532, + "owe": 12533, + "defenders": 12534, + "shiva": 12535, + "notorious": 12536, + "disbelief": 12537, + "shiny": 12538, + "worcester": 12539, + "##gation": 12540, + "##yr": 12541, + "trailing": 12542, + "undertook": 12543, + "islander": 12544, + "belarus": 12545, + "limitations": 12546, + "watershed": 12547, + "fuller": 12548, + "overlooking": 12549, + "utilized": 12550, + "raphael": 12551, + "1819": 12552, + "synthetic": 12553, + "breakdown": 12554, + "klein": 12555, + "##nate": 12556, + "moaned": 12557, + "memoir": 12558, + "lamb": 12559, + "practicing": 12560, + "##erly": 12561, + "cellular": 12562, + "arrows": 12563, + "exotic": 12564, + "##graphy": 12565, + "witches": 12566, + "117": 12567, + "charted": 12568, + "rey": 12569, + "hut": 12570, + "hierarchy": 12571, + "subdivision": 12572, + "freshwater": 12573, + "giuseppe": 12574, + "aloud": 12575, + "reyes": 12576, + "qatar": 12577, + "marty": 12578, + "sideways": 12579, + "utterly": 12580, + "sexually": 12581, + "jude": 12582, + "prayers": 12583, + "mccarthy": 12584, + "softball": 12585, + "blend": 12586, + "damien": 12587, + "##gging": 12588, + "##metric": 12589, + "wholly": 12590, + "erupted": 12591, + "lebanese": 12592, + "negro": 12593, + "revenues": 12594, + "tasted": 12595, + "comparative": 12596, + "teamed": 12597, + "transaction": 12598, + "labeled": 12599, + "maori": 12600, + "sovereignty": 12601, + "parkway": 12602, + "trauma": 12603, + "gran": 12604, + "malay": 12605, + "121": 12606, + "advancement": 12607, + "descendant": 12608, + "2020": 12609, + "buzz": 12610, + "salvation": 12611, + "inventory": 12612, + "symbolic": 12613, + "##making": 12614, + "antarctica": 12615, + "mps": 12616, + "##gas": 12617, + "##bro": 12618, + "mohammed": 12619, + "myanmar": 12620, + "holt": 12621, + "submarines": 12622, + "tones": 12623, + "##lman": 12624, + "locker": 12625, + "patriarch": 12626, + "bangkok": 12627, + "emerson": 12628, + "remarks": 12629, + "predators": 12630, + "kin": 12631, + "afghan": 12632, + "confession": 12633, + "norwich": 12634, + "rental": 12635, + "emerge": 12636, + "advantages": 12637, + "##zel": 12638, + "rca": 12639, + "##hold": 12640, + "shortened": 12641, + "storms": 12642, + "aidan": 12643, + "##matic": 12644, + "autonomy": 12645, + "compliance": 12646, + "##quet": 12647, + "dudley": 12648, + "atp": 12649, + "##osis": 12650, + "1803": 12651, + "motto": 12652, + "documentation": 12653, + "summary": 12654, + "professors": 12655, + "spectacular": 12656, + "christina": 12657, + "archdiocese": 12658, + "flashing": 12659, + "innocence": 12660, + "remake": 12661, + "##dell": 12662, + "psychic": 12663, + "reef": 12664, + "scare": 12665, + "employ": 12666, + "rs": 12667, + "sticks": 12668, + "meg": 12669, + "gus": 12670, + "leans": 12671, + "##ude": 12672, + "accompany": 12673, + "bergen": 12674, + "tomas": 12675, + "##iko": 12676, + "doom": 12677, + "wages": 12678, + "pools": 12679, + "##nch": 12680, + "##bes": 12681, + "breasts": 12682, + "scholarly": 12683, + "alison": 12684, + "outline": 12685, + "brittany": 12686, + "breakthrough": 12687, + "willis": 12688, + "realistic": 12689, + "##cut": 12690, + "##boro": 12691, + "competitor": 12692, + "##stan": 12693, + "pike": 12694, + "picnic": 12695, + "icon": 12696, + "designing": 12697, + "commercials": 12698, + "washing": 12699, + "villain": 12700, + "skiing": 12701, + "micro": 12702, + "costumes": 12703, + "auburn": 12704, + "halted": 12705, + "executives": 12706, + "##hat": 12707, + "logistics": 12708, + "cycles": 12709, + "vowel": 12710, + "applicable": 12711, + "barrett": 12712, + "exclaimed": 12713, + "eurovision": 12714, + "eternity": 12715, + "ramon": 12716, + "##umi": 12717, + "##lls": 12718, + "modifications": 12719, + "sweeping": 12720, + "disgust": 12721, + "##uck": 12722, + "torch": 12723, + "aviv": 12724, + "ensuring": 12725, + "rude": 12726, + "dusty": 12727, + "sonic": 12728, + "donovan": 12729, + "outskirts": 12730, + "cu": 12731, + "pathway": 12732, + "##band": 12733, + "##gun": 12734, + "##lines": 12735, + "disciplines": 12736, + "acids": 12737, + "cadet": 12738, + "paired": 12739, + "##40": 12740, + "sketches": 12741, + "##sive": 12742, + "marriages": 12743, + "##⁺": 12744, + "folding": 12745, + "peers": 12746, + "slovak": 12747, + "implies": 12748, + "admired": 12749, + "##beck": 12750, + "1880s": 12751, + "leopold": 12752, + "instinct": 12753, + "attained": 12754, + "weston": 12755, + "megan": 12756, + "horace": 12757, + "##ination": 12758, + "dorsal": 12759, + "ingredients": 12760, + "evolutionary": 12761, + "##its": 12762, + "complications": 12763, + "deity": 12764, + "lethal": 12765, + "brushing": 12766, + "levy": 12767, + "deserted": 12768, + "institutes": 12769, + "posthumously": 12770, + "delivering": 12771, + "telescope": 12772, + "coronation": 12773, + "motivated": 12774, + "rapids": 12775, + "luc": 12776, + "flicked": 12777, + "pays": 12778, + "volcano": 12779, + "tanner": 12780, + "weighed": 12781, + "##nica": 12782, + "crowds": 12783, + "frankie": 12784, + "gifted": 12785, + "addressing": 12786, + "granddaughter": 12787, + "winding": 12788, + "##rna": 12789, + "constantine": 12790, + "gomez": 12791, + "##front": 12792, + "landscapes": 12793, + "rudolf": 12794, + "anthropology": 12795, + "slate": 12796, + "werewolf": 12797, + "##lio": 12798, + "astronomy": 12799, + "circa": 12800, + "rouge": 12801, + "dreaming": 12802, + "sack": 12803, + "knelt": 12804, + "drowned": 12805, + "naomi": 12806, + "prolific": 12807, + "tracked": 12808, + "freezing": 12809, + "herb": 12810, + "##dium": 12811, + "agony": 12812, + "randall": 12813, + "twisting": 12814, + "wendy": 12815, + "deposit": 12816, + "touches": 12817, + "vein": 12818, + "wheeler": 12819, + "##bbled": 12820, + "##bor": 12821, + "batted": 12822, + "retaining": 12823, + "tire": 12824, + "presently": 12825, + "compare": 12826, + "specification": 12827, + "daemon": 12828, + "nigel": 12829, + "##grave": 12830, + "merry": 12831, + "recommendation": 12832, + "czechoslovakia": 12833, + "sandra": 12834, + "ng": 12835, + "roma": 12836, + "##sts": 12837, + "lambert": 12838, + "inheritance": 12839, + "sheikh": 12840, + "winchester": 12841, + "cries": 12842, + "examining": 12843, + "##yle": 12844, + "comeback": 12845, + "cuisine": 12846, + "nave": 12847, + "##iv": 12848, + "ko": 12849, + "retrieve": 12850, + "tomatoes": 12851, + "barker": 12852, + "polished": 12853, + "defining": 12854, + "irene": 12855, + "lantern": 12856, + "personalities": 12857, + "begging": 12858, + "tract": 12859, + "swore": 12860, + "1809": 12861, + "175": 12862, + "##gic": 12863, + "omaha": 12864, + "brotherhood": 12865, + "##rley": 12866, + "haiti": 12867, + "##ots": 12868, + "exeter": 12869, + "##ete": 12870, + "##zia": 12871, + "steele": 12872, + "dumb": 12873, + "pearson": 12874, + "210": 12875, + "surveyed": 12876, + "elisabeth": 12877, + "trends": 12878, + "##ef": 12879, + "fritz": 12880, + "##rf": 12881, + "premium": 12882, + "bugs": 12883, + "fraction": 12884, + "calmly": 12885, + "viking": 12886, + "##birds": 12887, + "tug": 12888, + "inserted": 12889, + "unusually": 12890, + "##ield": 12891, + "confronted": 12892, + "distress": 12893, + "crashing": 12894, + "brent": 12895, + "turks": 12896, + "resign": 12897, + "##olo": 12898, + "cambodia": 12899, + "gabe": 12900, + "sauce": 12901, + "##kal": 12902, + "evelyn": 12903, + "116": 12904, + "extant": 12905, + "clusters": 12906, + "quarry": 12907, + "teenagers": 12908, + "luna": 12909, + "##lers": 12910, + "##ister": 12911, + "affiliation": 12912, + "drill": 12913, + "##ashi": 12914, + "panthers": 12915, + "scenic": 12916, + "libya": 12917, + "anita": 12918, + "strengthen": 12919, + "inscriptions": 12920, + "##cated": 12921, + "lace": 12922, + "sued": 12923, + "judith": 12924, + "riots": 12925, + "##uted": 12926, + "mint": 12927, + "##eta": 12928, + "preparations": 12929, + "midst": 12930, + "dub": 12931, + "challenger": 12932, + "##vich": 12933, + "mock": 12934, + "cf": 12935, + "displaced": 12936, + "wicket": 12937, + "breaths": 12938, + "enables": 12939, + "schmidt": 12940, + "analyst": 12941, + "##lum": 12942, + "ag": 12943, + "highlight": 12944, + "automotive": 12945, + "axe": 12946, + "josef": 12947, + "newark": 12948, + "sufficiently": 12949, + "resembles": 12950, + "50th": 12951, + "##pal": 12952, + "flushed": 12953, + "mum": 12954, + "traits": 12955, + "##ante": 12956, + "commodore": 12957, + "incomplete": 12958, + "warming": 12959, + "titular": 12960, + "ceremonial": 12961, + "ethical": 12962, + "118": 12963, + "celebrating": 12964, + "eighteenth": 12965, + "cao": 12966, + "lima": 12967, + "medalist": 12968, + "mobility": 12969, + "strips": 12970, + "snakes": 12971, + "##city": 12972, + "miniature": 12973, + "zagreb": 12974, + "barton": 12975, + "escapes": 12976, + "umbrella": 12977, + "automated": 12978, + "doubted": 12979, + "differs": 12980, + "cooled": 12981, + "georgetown": 12982, + "dresden": 12983, + "cooked": 12984, + "fade": 12985, + "wyatt": 12986, + "rna": 12987, + "jacobs": 12988, + "carlton": 12989, + "abundant": 12990, + "stereo": 12991, + "boost": 12992, + "madras": 12993, + "inning": 12994, + "##hia": 12995, + "spur": 12996, + "ip": 12997, + "malayalam": 12998, + "begged": 12999, + "osaka": 13000, + "groan": 13001, + "escaping": 13002, + "charging": 13003, + "dose": 13004, + "vista": 13005, + "##aj": 13006, + "bud": 13007, + "papa": 13008, + "communists": 13009, + "advocates": 13010, + "edged": 13011, + "tri": 13012, + "##cent": 13013, + "resemble": 13014, + "peaking": 13015, + "necklace": 13016, + "fried": 13017, + "montenegro": 13018, + "saxony": 13019, + "goose": 13020, + "glances": 13021, + "stuttgart": 13022, + "curator": 13023, + "recruit": 13024, + "grocery": 13025, + "sympathetic": 13026, + "##tting": 13027, + "##fort": 13028, + "127": 13029, + "lotus": 13030, + "randolph": 13031, + "ancestor": 13032, + "##rand": 13033, + "succeeding": 13034, + "jupiter": 13035, + "1798": 13036, + "macedonian": 13037, + "##heads": 13038, + "hiking": 13039, + "1808": 13040, + "handing": 13041, + "fischer": 13042, + "##itive": 13043, + "garbage": 13044, + "node": 13045, + "##pies": 13046, + "prone": 13047, + "singular": 13048, + "papua": 13049, + "inclined": 13050, + "attractions": 13051, + "italia": 13052, + "pouring": 13053, + "motioned": 13054, + "grandma": 13055, + "garnered": 13056, + "jacksonville": 13057, + "corp": 13058, + "ego": 13059, + "ringing": 13060, + "aluminum": 13061, + "##hausen": 13062, + "ordering": 13063, + "##foot": 13064, + "drawer": 13065, + "traders": 13066, + "synagogue": 13067, + "##play": 13068, + "##kawa": 13069, + "resistant": 13070, + "wandering": 13071, + "fragile": 13072, + "fiona": 13073, + "teased": 13074, + "var": 13075, + "hardcore": 13076, + "soaked": 13077, + "jubilee": 13078, + "decisive": 13079, + "exposition": 13080, + "mercer": 13081, + "poster": 13082, + "valencia": 13083, + "hale": 13084, + "kuwait": 13085, + "1811": 13086, + "##ises": 13087, + "##wr": 13088, + "##eed": 13089, + "tavern": 13090, + "gamma": 13091, + "122": 13092, + "johan": 13093, + "##uer": 13094, + "airways": 13095, + "amino": 13096, + "gil": 13097, + "##ury": 13098, + "vocational": 13099, + "domains": 13100, + "torres": 13101, + "##sp": 13102, + "generator": 13103, + "folklore": 13104, + "outcomes": 13105, + "##keeper": 13106, + "canberra": 13107, + "shooter": 13108, + "fl": 13109, + "beams": 13110, + "confrontation": 13111, + "##lling": 13112, + "##gram": 13113, + "feb": 13114, + "aligned": 13115, + "forestry": 13116, + "pipeline": 13117, + "jax": 13118, + "motorway": 13119, + "conception": 13120, + "decay": 13121, + "##tos": 13122, + "coffin": 13123, + "##cott": 13124, + "stalin": 13125, + "1805": 13126, + "escorted": 13127, + "minded": 13128, + "##nam": 13129, + "sitcom": 13130, + "purchasing": 13131, + "twilight": 13132, + "veronica": 13133, + "additions": 13134, + "passive": 13135, + "tensions": 13136, + "straw": 13137, + "123": 13138, + "frequencies": 13139, + "1804": 13140, + "refugee": 13141, + "cultivation": 13142, + "##iate": 13143, + "christie": 13144, + "clary": 13145, + "bulletin": 13146, + "crept": 13147, + "disposal": 13148, + "##rich": 13149, + "##zong": 13150, + "processor": 13151, + "crescent": 13152, + "##rol": 13153, + "bmw": 13154, + "emphasized": 13155, + "whale": 13156, + "nazis": 13157, + "aurora": 13158, + "##eng": 13159, + "dwelling": 13160, + "hauled": 13161, + "sponsors": 13162, + "toledo": 13163, + "mega": 13164, + "ideology": 13165, + "theatres": 13166, + "tessa": 13167, + "cerambycidae": 13168, + "saves": 13169, + "turtle": 13170, + "cone": 13171, + "suspects": 13172, + "kara": 13173, + "rusty": 13174, + "yelling": 13175, + "greeks": 13176, + "mozart": 13177, + "shades": 13178, + "cocked": 13179, + "participant": 13180, + "##tro": 13181, + "shire": 13182, + "spit": 13183, + "freeze": 13184, + "necessity": 13185, + "##cos": 13186, + "inmates": 13187, + "nielsen": 13188, + "councillors": 13189, + "loaned": 13190, + "uncommon": 13191, + "omar": 13192, + "peasants": 13193, + "botanical": 13194, + "offspring": 13195, + "daniels": 13196, + "formations": 13197, + "jokes": 13198, + "1794": 13199, + "pioneers": 13200, + "sigma": 13201, + "licensing": 13202, + "##sus": 13203, + "wheelchair": 13204, + "polite": 13205, + "1807": 13206, + "liquor": 13207, + "pratt": 13208, + "trustee": 13209, + "##uta": 13210, + "forewings": 13211, + "balloon": 13212, + "##zz": 13213, + "kilometre": 13214, + "camping": 13215, + "explicit": 13216, + "casually": 13217, + "shawn": 13218, + "foolish": 13219, + "teammates": 13220, + "nm": 13221, + "hassan": 13222, + "carrie": 13223, + "judged": 13224, + "satisfy": 13225, + "vanessa": 13226, + "knives": 13227, + "selective": 13228, + "cnn": 13229, + "flowed": 13230, + "##lice": 13231, + "eclipse": 13232, + "stressed": 13233, + "eliza": 13234, + "mathematician": 13235, + "cease": 13236, + "cultivated": 13237, + "##roy": 13238, + "commissions": 13239, + "browns": 13240, + "##ania": 13241, + "destroyers": 13242, + "sheridan": 13243, + "meadow": 13244, + "##rius": 13245, + "minerals": 13246, + "##cial": 13247, + "downstream": 13248, + "clash": 13249, + "gram": 13250, + "memoirs": 13251, + "ventures": 13252, + "baha": 13253, + "seymour": 13254, + "archie": 13255, + "midlands": 13256, + "edith": 13257, + "fare": 13258, + "flynn": 13259, + "invite": 13260, + "canceled": 13261, + "tiles": 13262, + "stabbed": 13263, + "boulder": 13264, + "incorporate": 13265, + "amended": 13266, + "camden": 13267, + "facial": 13268, + "mollusk": 13269, + "unreleased": 13270, + "descriptions": 13271, + "yoga": 13272, + "grabs": 13273, + "550": 13274, + "raises": 13275, + "ramp": 13276, + "shiver": 13277, + "##rose": 13278, + "coined": 13279, + "pioneering": 13280, + "tunes": 13281, + "qing": 13282, + "warwick": 13283, + "tops": 13284, + "119": 13285, + "melanie": 13286, + "giles": 13287, + "##rous": 13288, + "wandered": 13289, + "##inal": 13290, + "annexed": 13291, + "nov": 13292, + "30th": 13293, + "unnamed": 13294, + "##ished": 13295, + "organizational": 13296, + "airplane": 13297, + "normandy": 13298, + "stoke": 13299, + "whistle": 13300, + "blessing": 13301, + "violations": 13302, + "chased": 13303, + "holders": 13304, + "shotgun": 13305, + "##ctic": 13306, + "outlet": 13307, + "reactor": 13308, + "##vik": 13309, + "tires": 13310, + "tearing": 13311, + "shores": 13312, + "fortified": 13313, + "mascot": 13314, + "constituencies": 13315, + "nc": 13316, + "columnist": 13317, + "productive": 13318, + "tibet": 13319, + "##rta": 13320, + "lineage": 13321, + "hooked": 13322, + "oct": 13323, + "tapes": 13324, + "judging": 13325, + "cody": 13326, + "##gger": 13327, + "hansen": 13328, + "kashmir": 13329, + "triggered": 13330, + "##eva": 13331, + "solved": 13332, + "cliffs": 13333, + "##tree": 13334, + "resisted": 13335, + "anatomy": 13336, + "protesters": 13337, + "transparent": 13338, + "implied": 13339, + "##iga": 13340, + "injection": 13341, + "mattress": 13342, + "excluding": 13343, + "##mbo": 13344, + "defenses": 13345, + "helpless": 13346, + "devotion": 13347, + "##elli": 13348, + "growl": 13349, + "liberals": 13350, + "weber": 13351, + "phenomena": 13352, + "atoms": 13353, + "plug": 13354, + "##iff": 13355, + "mortality": 13356, + "apprentice": 13357, + "howe": 13358, + "convincing": 13359, + "aaa": 13360, + "swimmer": 13361, + "barber": 13362, + "leone": 13363, + "promptly": 13364, + "sodium": 13365, + "def": 13366, + "nowadays": 13367, + "arise": 13368, + "##oning": 13369, + "gloucester": 13370, + "corrected": 13371, + "dignity": 13372, + "norm": 13373, + "erie": 13374, + "##ders": 13375, + "elders": 13376, + "evacuated": 13377, + "sylvia": 13378, + "compression": 13379, + "##yar": 13380, + "hartford": 13381, + "pose": 13382, + "backpack": 13383, + "reasoning": 13384, + "accepts": 13385, + "24th": 13386, + "wipe": 13387, + "millimetres": 13388, + "marcel": 13389, + "##oda": 13390, + "dodgers": 13391, + "albion": 13392, + "1790": 13393, + "overwhelmed": 13394, + "aerospace": 13395, + "oaks": 13396, + "1795": 13397, + "showcase": 13398, + "acknowledge": 13399, + "recovering": 13400, + "nolan": 13401, + "ashe": 13402, + "hurts": 13403, + "geology": 13404, + "fashioned": 13405, + "disappearance": 13406, + "farewell": 13407, + "swollen": 13408, + "shrug": 13409, + "marquis": 13410, + "wimbledon": 13411, + "124": 13412, + "rue": 13413, + "1792": 13414, + "commemorate": 13415, + "reduces": 13416, + "experiencing": 13417, + "inevitable": 13418, + "calcutta": 13419, + "intel": 13420, + "##court": 13421, + "murderer": 13422, + "sticking": 13423, + "fisheries": 13424, + "imagery": 13425, + "bloom": 13426, + "280": 13427, + "brake": 13428, + "##inus": 13429, + "gustav": 13430, + "hesitation": 13431, + "memorable": 13432, + "po": 13433, + "viral": 13434, + "beans": 13435, + "accidents": 13436, + "tunisia": 13437, + "antenna": 13438, + "spilled": 13439, + "consort": 13440, + "treatments": 13441, + "aye": 13442, + "perimeter": 13443, + "##gard": 13444, + "donation": 13445, + "hostage": 13446, + "migrated": 13447, + "banker": 13448, + "addiction": 13449, + "apex": 13450, + "lil": 13451, + "trout": 13452, + "##ously": 13453, + "conscience": 13454, + "##nova": 13455, + "rams": 13456, + "sands": 13457, + "genome": 13458, + "passionate": 13459, + "troubles": 13460, + "##lets": 13461, + "##set": 13462, + "amid": 13463, + "##ibility": 13464, + "##ret": 13465, + "higgins": 13466, + "exceed": 13467, + "vikings": 13468, + "##vie": 13469, + "payne": 13470, + "##zan": 13471, + "muscular": 13472, + "##ste": 13473, + "defendant": 13474, + "sucking": 13475, + "##wal": 13476, + "ibrahim": 13477, + "fuselage": 13478, + "claudia": 13479, + "vfl": 13480, + "europeans": 13481, + "snails": 13482, + "interval": 13483, + "##garh": 13484, + "preparatory": 13485, + "statewide": 13486, + "tasked": 13487, + "lacrosse": 13488, + "viktor": 13489, + "##lation": 13490, + "angola": 13491, + "##hra": 13492, + "flint": 13493, + "implications": 13494, + "employs": 13495, + "teens": 13496, + "patrons": 13497, + "stall": 13498, + "weekends": 13499, + "barriers": 13500, + "scrambled": 13501, + "nucleus": 13502, + "tehran": 13503, + "jenna": 13504, + "parsons": 13505, + "lifelong": 13506, + "robots": 13507, + "displacement": 13508, + "5000": 13509, + "##bles": 13510, + "precipitation": 13511, + "##gt": 13512, + "knuckles": 13513, + "clutched": 13514, + "1802": 13515, + "marrying": 13516, + "ecology": 13517, + "marx": 13518, + "accusations": 13519, + "declare": 13520, + "scars": 13521, + "kolkata": 13522, + "mat": 13523, + "meadows": 13524, + "bermuda": 13525, + "skeleton": 13526, + "finalists": 13527, + "vintage": 13528, + "crawl": 13529, + "coordinate": 13530, + "affects": 13531, + "subjected": 13532, + "orchestral": 13533, + "mistaken": 13534, + "##tc": 13535, + "mirrors": 13536, + "dipped": 13537, + "relied": 13538, + "260": 13539, + "arches": 13540, + "candle": 13541, + "##nick": 13542, + "incorporating": 13543, + "wildly": 13544, + "fond": 13545, + "basilica": 13546, + "owl": 13547, + "fringe": 13548, + "rituals": 13549, + "whispering": 13550, + "stirred": 13551, + "feud": 13552, + "tertiary": 13553, + "slick": 13554, + "goat": 13555, + "honorable": 13556, + "whereby": 13557, + "skip": 13558, + "ricardo": 13559, + "stripes": 13560, + "parachute": 13561, + "adjoining": 13562, + "submerged": 13563, + "synthesizer": 13564, + "##gren": 13565, + "intend": 13566, + "positively": 13567, + "ninety": 13568, + "phi": 13569, + "beaver": 13570, + "partition": 13571, + "fellows": 13572, + "alexis": 13573, + "prohibition": 13574, + "carlisle": 13575, + "bizarre": 13576, + "fraternity": 13577, + "##bre": 13578, + "doubts": 13579, + "icy": 13580, + "cbc": 13581, + "aquatic": 13582, + "sneak": 13583, + "sonny": 13584, + "combines": 13585, + "airports": 13586, + "crude": 13587, + "supervised": 13588, + "spatial": 13589, + "merge": 13590, + "alfonso": 13591, + "##bic": 13592, + "corrupt": 13593, + "scan": 13594, + "undergo": 13595, + "##ams": 13596, + "disabilities": 13597, + "colombian": 13598, + "comparing": 13599, + "dolphins": 13600, + "perkins": 13601, + "##lish": 13602, + "reprinted": 13603, + "unanimous": 13604, + "bounced": 13605, + "hairs": 13606, + "underworld": 13607, + "midwest": 13608, + "semester": 13609, + "bucket": 13610, + "paperback": 13611, + "miniseries": 13612, + "coventry": 13613, + "demise": 13614, + "##leigh": 13615, + "demonstrations": 13616, + "sensor": 13617, + "rotating": 13618, + "yan": 13619, + "##hler": 13620, + "arrange": 13621, + "soils": 13622, + "##idge": 13623, + "hyderabad": 13624, + "labs": 13625, + "##dr": 13626, + "brakes": 13627, + "grandchildren": 13628, + "##nde": 13629, + "negotiated": 13630, + "rover": 13631, + "ferrari": 13632, + "continuation": 13633, + "directorate": 13634, + "augusta": 13635, + "stevenson": 13636, + "counterpart": 13637, + "gore": 13638, + "##rda": 13639, + "nursery": 13640, + "rican": 13641, + "ave": 13642, + "collectively": 13643, + "broadly": 13644, + "pastoral": 13645, + "repertoire": 13646, + "asserted": 13647, + "discovering": 13648, + "nordic": 13649, + "styled": 13650, + "fiba": 13651, + "cunningham": 13652, + "harley": 13653, + "middlesex": 13654, + "survives": 13655, + "tumor": 13656, + "tempo": 13657, + "zack": 13658, + "aiming": 13659, + "lok": 13660, + "urgent": 13661, + "##rade": 13662, + "##nto": 13663, + "devils": 13664, + "##ement": 13665, + "contractor": 13666, + "turin": 13667, + "##wl": 13668, + "##ool": 13669, + "bliss": 13670, + "repaired": 13671, + "simmons": 13672, + "moan": 13673, + "astronomical": 13674, + "cr": 13675, + "negotiate": 13676, + "lyric": 13677, + "1890s": 13678, + "lara": 13679, + "bred": 13680, + "clad": 13681, + "angus": 13682, + "pbs": 13683, + "##ience": 13684, + "engineered": 13685, + "posed": 13686, + "##lk": 13687, + "hernandez": 13688, + "possessions": 13689, + "elbows": 13690, + "psychiatric": 13691, + "strokes": 13692, + "confluence": 13693, + "electorate": 13694, + "lifts": 13695, + "campuses": 13696, + "lava": 13697, + "alps": 13698, + "##ep": 13699, + "##ution": 13700, + "##date": 13701, + "physicist": 13702, + "woody": 13703, + "##page": 13704, + "##ographic": 13705, + "##itis": 13706, + "juliet": 13707, + "reformation": 13708, + "sparhawk": 13709, + "320": 13710, + "complement": 13711, + "suppressed": 13712, + "jewel": 13713, + "##½": 13714, + "floated": 13715, + "##kas": 13716, + "continuity": 13717, + "sadly": 13718, + "##ische": 13719, + "inability": 13720, + "melting": 13721, + "scanning": 13722, + "paula": 13723, + "flour": 13724, + "judaism": 13725, + "safer": 13726, + "vague": 13727, + "##lm": 13728, + "solving": 13729, + "curb": 13730, + "##stown": 13731, + "financially": 13732, + "gable": 13733, + "bees": 13734, + "expired": 13735, + "miserable": 13736, + "cassidy": 13737, + "dominion": 13738, + "1789": 13739, + "cupped": 13740, + "145": 13741, + "robbery": 13742, + "facto": 13743, + "amos": 13744, + "warden": 13745, + "resume": 13746, + "tallest": 13747, + "marvin": 13748, + "ing": 13749, + "pounded": 13750, + "usd": 13751, + "declaring": 13752, + "gasoline": 13753, + "##aux": 13754, + "darkened": 13755, + "270": 13756, + "650": 13757, + "sophomore": 13758, + "##mere": 13759, + "erection": 13760, + "gossip": 13761, + "televised": 13762, + "risen": 13763, + "dial": 13764, + "##eu": 13765, + "pillars": 13766, + "##link": 13767, + "passages": 13768, + "profound": 13769, + "##tina": 13770, + "arabian": 13771, + "ashton": 13772, + "silicon": 13773, + "nail": 13774, + "##ead": 13775, + "##lated": 13776, + "##wer": 13777, + "##hardt": 13778, + "fleming": 13779, + "firearms": 13780, + "ducked": 13781, + "circuits": 13782, + "blows": 13783, + "waterloo": 13784, + "titans": 13785, + "##lina": 13786, + "atom": 13787, + "fireplace": 13788, + "cheshire": 13789, + "financed": 13790, + "activation": 13791, + "algorithms": 13792, + "##zzi": 13793, + "constituent": 13794, + "catcher": 13795, + "cherokee": 13796, + "partnerships": 13797, + "sexuality": 13798, + "platoon": 13799, + "tragic": 13800, + "vivian": 13801, + "guarded": 13802, + "whiskey": 13803, + "meditation": 13804, + "poetic": 13805, + "##late": 13806, + "##nga": 13807, + "##ake": 13808, + "porto": 13809, + "listeners": 13810, + "dominance": 13811, + "kendra": 13812, + "mona": 13813, + "chandler": 13814, + "factions": 13815, + "22nd": 13816, + "salisbury": 13817, + "attitudes": 13818, + "derivative": 13819, + "##ido": 13820, + "##haus": 13821, + "intake": 13822, + "paced": 13823, + "javier": 13824, + "illustrator": 13825, + "barrels": 13826, + "bias": 13827, + "cockpit": 13828, + "burnett": 13829, + "dreamed": 13830, + "ensuing": 13831, + "##anda": 13832, + "receptors": 13833, + "someday": 13834, + "hawkins": 13835, + "mattered": 13836, + "##lal": 13837, + "slavic": 13838, + "1799": 13839, + "jesuit": 13840, + "cameroon": 13841, + "wasted": 13842, + "tai": 13843, + "wax": 13844, + "lowering": 13845, + "victorious": 13846, + "freaking": 13847, + "outright": 13848, + "hancock": 13849, + "librarian": 13850, + "sensing": 13851, + "bald": 13852, + "calcium": 13853, + "myers": 13854, + "tablet": 13855, + "announcing": 13856, + "barack": 13857, + "shipyard": 13858, + "pharmaceutical": 13859, + "##uan": 13860, + "greenwich": 13861, + "flush": 13862, + "medley": 13863, + "patches": 13864, + "wolfgang": 13865, + "pt": 13866, + "speeches": 13867, + "acquiring": 13868, + "exams": 13869, + "nikolai": 13870, + "##gg": 13871, + "hayden": 13872, + "kannada": 13873, + "##type": 13874, + "reilly": 13875, + "##pt": 13876, + "waitress": 13877, + "abdomen": 13878, + "devastated": 13879, + "capped": 13880, + "pseudonym": 13881, + "pharmacy": 13882, + "fulfill": 13883, + "paraguay": 13884, + "1796": 13885, + "clicked": 13886, + "##trom": 13887, + "archipelago": 13888, + "syndicated": 13889, + "##hman": 13890, + "lumber": 13891, + "orgasm": 13892, + "rejection": 13893, + "clifford": 13894, + "lorraine": 13895, + "advent": 13896, + "mafia": 13897, + "rodney": 13898, + "brock": 13899, + "##ght": 13900, + "##used": 13901, + "##elia": 13902, + "cassette": 13903, + "chamberlain": 13904, + "despair": 13905, + "mongolia": 13906, + "sensors": 13907, + "developmental": 13908, + "upstream": 13909, + "##eg": 13910, + "##alis": 13911, + "spanning": 13912, + "165": 13913, + "trombone": 13914, + "basque": 13915, + "seeded": 13916, + "interred": 13917, + "renewable": 13918, + "rhys": 13919, + "leapt": 13920, + "revision": 13921, + "molecule": 13922, + "##ages": 13923, + "chord": 13924, + "vicious": 13925, + "nord": 13926, + "shivered": 13927, + "23rd": 13928, + "arlington": 13929, + "debts": 13930, + "corpus": 13931, + "sunrise": 13932, + "bays": 13933, + "blackburn": 13934, + "centimetres": 13935, + "##uded": 13936, + "shuddered": 13937, + "gm": 13938, + "strangely": 13939, + "gripping": 13940, + "cartoons": 13941, + "isabelle": 13942, + "orbital": 13943, + "##ppa": 13944, + "seals": 13945, + "proving": 13946, + "##lton": 13947, + "refusal": 13948, + "strengthened": 13949, + "bust": 13950, + "assisting": 13951, + "baghdad": 13952, + "batsman": 13953, + "portrayal": 13954, + "mara": 13955, + "pushes": 13956, + "spears": 13957, + "og": 13958, + "##cock": 13959, + "reside": 13960, + "nathaniel": 13961, + "brennan": 13962, + "1776": 13963, + "confirmation": 13964, + "caucus": 13965, + "##worthy": 13966, + "markings": 13967, + "yemen": 13968, + "nobles": 13969, + "ku": 13970, + "lazy": 13971, + "viewer": 13972, + "catalan": 13973, + "encompasses": 13974, + "sawyer": 13975, + "##fall": 13976, + "sparked": 13977, + "substances": 13978, + "patents": 13979, + "braves": 13980, + "arranger": 13981, + "evacuation": 13982, + "sergio": 13983, + "persuade": 13984, + "dover": 13985, + "tolerance": 13986, + "penguin": 13987, + "cum": 13988, + "jockey": 13989, + "insufficient": 13990, + "townships": 13991, + "occupying": 13992, + "declining": 13993, + "plural": 13994, + "processed": 13995, + "projection": 13996, + "puppet": 13997, + "flanders": 13998, + "introduces": 13999, + "liability": 14000, + "##yon": 14001, + "gymnastics": 14002, + "antwerp": 14003, + "taipei": 14004, + "hobart": 14005, + "candles": 14006, + "jeep": 14007, + "wes": 14008, + "observers": 14009, + "126": 14010, + "chaplain": 14011, + "bundle": 14012, + "glorious": 14013, + "##hine": 14014, + "hazel": 14015, + "flung": 14016, + "sol": 14017, + "excavations": 14018, + "dumped": 14019, + "stares": 14020, + "sh": 14021, + "bangalore": 14022, + "triangular": 14023, + "icelandic": 14024, + "intervals": 14025, + "expressing": 14026, + "turbine": 14027, + "##vers": 14028, + "songwriting": 14029, + "crafts": 14030, + "##igo": 14031, + "jasmine": 14032, + "ditch": 14033, + "rite": 14034, + "##ways": 14035, + "entertaining": 14036, + "comply": 14037, + "sorrow": 14038, + "wrestlers": 14039, + "basel": 14040, + "emirates": 14041, + "marian": 14042, + "rivera": 14043, + "helpful": 14044, + "##some": 14045, + "caution": 14046, + "downward": 14047, + "networking": 14048, + "##atory": 14049, + "##tered": 14050, + "darted": 14051, + "genocide": 14052, + "emergence": 14053, + "replies": 14054, + "specializing": 14055, + "spokesman": 14056, + "convenient": 14057, + "unlocked": 14058, + "fading": 14059, + "augustine": 14060, + "concentrations": 14061, + "resemblance": 14062, + "elijah": 14063, + "investigator": 14064, + "andhra": 14065, + "##uda": 14066, + "promotes": 14067, + "bean": 14068, + "##rrell": 14069, + "fleeing": 14070, + "wan": 14071, + "simone": 14072, + "announcer": 14073, + "##ame": 14074, + "##bby": 14075, + "lydia": 14076, + "weaver": 14077, + "132": 14078, + "residency": 14079, + "modification": 14080, + "##fest": 14081, + "stretches": 14082, + "##ast": 14083, + "alternatively": 14084, + "nat": 14085, + "lowe": 14086, + "lacks": 14087, + "##ented": 14088, + "pam": 14089, + "tile": 14090, + "concealed": 14091, + "inferior": 14092, + "abdullah": 14093, + "residences": 14094, + "tissues": 14095, + "vengeance": 14096, + "##ided": 14097, + "moisture": 14098, + "peculiar": 14099, + "groove": 14100, + "zip": 14101, + "bologna": 14102, + "jennings": 14103, + "ninja": 14104, + "oversaw": 14105, + "zombies": 14106, + "pumping": 14107, + "batch": 14108, + "livingston": 14109, + "emerald": 14110, + "installations": 14111, + "1797": 14112, + "peel": 14113, + "nitrogen": 14114, + "rama": 14115, + "##fying": 14116, + "##star": 14117, + "schooling": 14118, + "strands": 14119, + "responding": 14120, + "werner": 14121, + "##ost": 14122, + "lime": 14123, + "casa": 14124, + "accurately": 14125, + "targeting": 14126, + "##rod": 14127, + "underway": 14128, + "##uru": 14129, + "hemisphere": 14130, + "lester": 14131, + "##yard": 14132, + "occupies": 14133, + "2d": 14134, + "griffith": 14135, + "angrily": 14136, + "reorganized": 14137, + "##owing": 14138, + "courtney": 14139, + "deposited": 14140, + "##dd": 14141, + "##30": 14142, + "estadio": 14143, + "##ifies": 14144, + "dunn": 14145, + "exiled": 14146, + "##ying": 14147, + "checks": 14148, + "##combe": 14149, + "##о": 14150, + "##fly": 14151, + "successes": 14152, + "unexpectedly": 14153, + "blu": 14154, + "assessed": 14155, + "##flower": 14156, + "##ه": 14157, + "observing": 14158, + "sacked": 14159, + "spiders": 14160, + "kn": 14161, + "##tail": 14162, + "mu": 14163, + "nodes": 14164, + "prosperity": 14165, + "audrey": 14166, + "divisional": 14167, + "155": 14168, + "broncos": 14169, + "tangled": 14170, + "adjust": 14171, + "feeds": 14172, + "erosion": 14173, + "paolo": 14174, + "surf": 14175, + "directory": 14176, + "snatched": 14177, + "humid": 14178, + "admiralty": 14179, + "screwed": 14180, + "gt": 14181, + "reddish": 14182, + "##nese": 14183, + "modules": 14184, + "trench": 14185, + "lamps": 14186, + "bind": 14187, + "leah": 14188, + "bucks": 14189, + "competes": 14190, + "##nz": 14191, + "##form": 14192, + "transcription": 14193, + "##uc": 14194, + "isles": 14195, + "violently": 14196, + "clutching": 14197, + "pga": 14198, + "cyclist": 14199, + "inflation": 14200, + "flats": 14201, + "ragged": 14202, + "unnecessary": 14203, + "##hian": 14204, + "stubborn": 14205, + "coordinated": 14206, + "harriet": 14207, + "baba": 14208, + "disqualified": 14209, + "330": 14210, + "insect": 14211, + "wolfe": 14212, + "##fies": 14213, + "reinforcements": 14214, + "rocked": 14215, + "duel": 14216, + "winked": 14217, + "embraced": 14218, + "bricks": 14219, + "##raj": 14220, + "hiatus": 14221, + "defeats": 14222, + "pending": 14223, + "brightly": 14224, + "jealousy": 14225, + "##xton": 14226, + "##hm": 14227, + "##uki": 14228, + "lena": 14229, + "gdp": 14230, + "colorful": 14231, + "##dley": 14232, + "stein": 14233, + "kidney": 14234, + "##shu": 14235, + "underwear": 14236, + "wanderers": 14237, + "##haw": 14238, + "##icus": 14239, + "guardians": 14240, + "m³": 14241, + "roared": 14242, + "habits": 14243, + "##wise": 14244, + "permits": 14245, + "gp": 14246, + "uranium": 14247, + "punished": 14248, + "disguise": 14249, + "bundesliga": 14250, + "elise": 14251, + "dundee": 14252, + "erotic": 14253, + "partisan": 14254, + "pi": 14255, + "collectors": 14256, + "float": 14257, + "individually": 14258, + "rendering": 14259, + "behavioral": 14260, + "bucharest": 14261, + "ser": 14262, + "hare": 14263, + "valerie": 14264, + "corporal": 14265, + "nutrition": 14266, + "proportional": 14267, + "##isa": 14268, + "immense": 14269, + "##kis": 14270, + "pavement": 14271, + "##zie": 14272, + "##eld": 14273, + "sutherland": 14274, + "crouched": 14275, + "1775": 14276, + "##lp": 14277, + "suzuki": 14278, + "trades": 14279, + "endurance": 14280, + "operas": 14281, + "crosby": 14282, + "prayed": 14283, + "priory": 14284, + "rory": 14285, + "socially": 14286, + "##urn": 14287, + "gujarat": 14288, + "##pu": 14289, + "walton": 14290, + "cube": 14291, + "pasha": 14292, + "privilege": 14293, + "lennon": 14294, + "floods": 14295, + "thorne": 14296, + "waterfall": 14297, + "nipple": 14298, + "scouting": 14299, + "approve": 14300, + "##lov": 14301, + "minorities": 14302, + "voter": 14303, + "dwight": 14304, + "extensions": 14305, + "assure": 14306, + "ballroom": 14307, + "slap": 14308, + "dripping": 14309, + "privileges": 14310, + "rejoined": 14311, + "confessed": 14312, + "demonstrating": 14313, + "patriotic": 14314, + "yell": 14315, + "investor": 14316, + "##uth": 14317, + "pagan": 14318, + "slumped": 14319, + "squares": 14320, + "##cle": 14321, + "##kins": 14322, + "confront": 14323, + "bert": 14324, + "embarrassment": 14325, + "##aid": 14326, + "aston": 14327, + "urging": 14328, + "sweater": 14329, + "starr": 14330, + "yuri": 14331, + "brains": 14332, + "williamson": 14333, + "commuter": 14334, + "mortar": 14335, + "structured": 14336, + "selfish": 14337, + "exports": 14338, + "##jon": 14339, + "cds": 14340, + "##him": 14341, + "unfinished": 14342, + "##rre": 14343, + "mortgage": 14344, + "destinations": 14345, + "##nagar": 14346, + "canoe": 14347, + "solitary": 14348, + "buchanan": 14349, + "delays": 14350, + "magistrate": 14351, + "fk": 14352, + "##pling": 14353, + "motivation": 14354, + "##lier": 14355, + "##vier": 14356, + "recruiting": 14357, + "assess": 14358, + "##mouth": 14359, + "malik": 14360, + "antique": 14361, + "1791": 14362, + "pius": 14363, + "rahman": 14364, + "reich": 14365, + "tub": 14366, + "zhou": 14367, + "smashed": 14368, + "airs": 14369, + "galway": 14370, + "xii": 14371, + "conditioning": 14372, + "honduras": 14373, + "discharged": 14374, + "dexter": 14375, + "##pf": 14376, + "lionel": 14377, + "129": 14378, + "debates": 14379, + "lemon": 14380, + "tiffany": 14381, + "volunteered": 14382, + "dom": 14383, + "dioxide": 14384, + "procession": 14385, + "devi": 14386, + "sic": 14387, + "tremendous": 14388, + "advertisements": 14389, + "colts": 14390, + "transferring": 14391, + "verdict": 14392, + "hanover": 14393, + "decommissioned": 14394, + "utter": 14395, + "relate": 14396, + "pac": 14397, + "racism": 14398, + "##top": 14399, + "beacon": 14400, + "limp": 14401, + "similarity": 14402, + "terra": 14403, + "occurrence": 14404, + "ant": 14405, + "##how": 14406, + "becky": 14407, + "capt": 14408, + "updates": 14409, + "armament": 14410, + "richie": 14411, + "pal": 14412, + "##graph": 14413, + "halloween": 14414, + "mayo": 14415, + "##ssen": 14416, + "##bone": 14417, + "cara": 14418, + "serena": 14419, + "fcc": 14420, + "dolls": 14421, + "obligations": 14422, + "##dling": 14423, + "violated": 14424, + "lafayette": 14425, + "jakarta": 14426, + "exploitation": 14427, + "##ime": 14428, + "infamous": 14429, + "iconic": 14430, + "##lah": 14431, + "##park": 14432, + "kitty": 14433, + "moody": 14434, + "reginald": 14435, + "dread": 14436, + "spill": 14437, + "crystals": 14438, + "olivier": 14439, + "modeled": 14440, + "bluff": 14441, + "equilibrium": 14442, + "separating": 14443, + "notices": 14444, + "ordnance": 14445, + "extinction": 14446, + "onset": 14447, + "cosmic": 14448, + "attachment": 14449, + "sammy": 14450, + "expose": 14451, + "privy": 14452, + "anchored": 14453, + "##bil": 14454, + "abbott": 14455, + "admits": 14456, + "bending": 14457, + "baritone": 14458, + "emmanuel": 14459, + "policeman": 14460, + "vaughan": 14461, + "winged": 14462, + "climax": 14463, + "dresses": 14464, + "denny": 14465, + "polytechnic": 14466, + "mohamed": 14467, + "burmese": 14468, + "authentic": 14469, + "nikki": 14470, + "genetics": 14471, + "grandparents": 14472, + "homestead": 14473, + "gaza": 14474, + "postponed": 14475, + "metacritic": 14476, + "una": 14477, + "##sby": 14478, + "##bat": 14479, + "unstable": 14480, + "dissertation": 14481, + "##rial": 14482, + "##cian": 14483, + "curls": 14484, + "obscure": 14485, + "uncovered": 14486, + "bronx": 14487, + "praying": 14488, + "disappearing": 14489, + "##hoe": 14490, + "prehistoric": 14491, + "coke": 14492, + "turret": 14493, + "mutations": 14494, + "nonprofit": 14495, + "pits": 14496, + "monaco": 14497, + "##ي": 14498, + "##usion": 14499, + "prominently": 14500, + "dispatched": 14501, + "podium": 14502, + "##mir": 14503, + "uci": 14504, + "##uation": 14505, + "133": 14506, + "fortifications": 14507, + "birthplace": 14508, + "kendall": 14509, + "##lby": 14510, + "##oll": 14511, + "preacher": 14512, + "rack": 14513, + "goodman": 14514, + "##rman": 14515, + "persistent": 14516, + "##ott": 14517, + "countless": 14518, + "jaime": 14519, + "recorder": 14520, + "lexington": 14521, + "persecution": 14522, + "jumps": 14523, + "renewal": 14524, + "wagons": 14525, + "##11": 14526, + "crushing": 14527, + "##holder": 14528, + "decorations": 14529, + "##lake": 14530, + "abundance": 14531, + "wrath": 14532, + "laundry": 14533, + "£1": 14534, + "garde": 14535, + "##rp": 14536, + "jeanne": 14537, + "beetles": 14538, + "peasant": 14539, + "##sl": 14540, + "splitting": 14541, + "caste": 14542, + "sergei": 14543, + "##rer": 14544, + "##ema": 14545, + "scripts": 14546, + "##ively": 14547, + "rub": 14548, + "satellites": 14549, + "##vor": 14550, + "inscribed": 14551, + "verlag": 14552, + "scrapped": 14553, + "gale": 14554, + "packages": 14555, + "chick": 14556, + "potato": 14557, + "slogan": 14558, + "kathleen": 14559, + "arabs": 14560, + "##culture": 14561, + "counterparts": 14562, + "reminiscent": 14563, + "choral": 14564, + "##tead": 14565, + "rand": 14566, + "retains": 14567, + "bushes": 14568, + "dane": 14569, + "accomplish": 14570, + "courtesy": 14571, + "closes": 14572, + "##oth": 14573, + "slaughter": 14574, + "hague": 14575, + "krakow": 14576, + "lawson": 14577, + "tailed": 14578, + "elias": 14579, + "ginger": 14580, + "##ttes": 14581, + "canopy": 14582, + "betrayal": 14583, + "rebuilding": 14584, + "turf": 14585, + "##hof": 14586, + "frowning": 14587, + "allegiance": 14588, + "brigades": 14589, + "kicks": 14590, + "rebuild": 14591, + "polls": 14592, + "alias": 14593, + "nationalism": 14594, + "td": 14595, + "rowan": 14596, + "audition": 14597, + "bowie": 14598, + "fortunately": 14599, + "recognizes": 14600, + "harp": 14601, + "dillon": 14602, + "horrified": 14603, + "##oro": 14604, + "renault": 14605, + "##tics": 14606, + "ropes": 14607, + "##α": 14608, + "presumed": 14609, + "rewarded": 14610, + "infrared": 14611, + "wiping": 14612, + "accelerated": 14613, + "illustration": 14614, + "##rid": 14615, + "presses": 14616, + "practitioners": 14617, + "badminton": 14618, + "##iard": 14619, + "detained": 14620, + "##tera": 14621, + "recognizing": 14622, + "relates": 14623, + "misery": 14624, + "##sies": 14625, + "##tly": 14626, + "reproduction": 14627, + "piercing": 14628, + "potatoes": 14629, + "thornton": 14630, + "esther": 14631, + "manners": 14632, + "hbo": 14633, + "##aan": 14634, + "ours": 14635, + "bullshit": 14636, + "ernie": 14637, + "perennial": 14638, + "sensitivity": 14639, + "illuminated": 14640, + "rupert": 14641, + "##jin": 14642, + "##iss": 14643, + "##ear": 14644, + "rfc": 14645, + "nassau": 14646, + "##dock": 14647, + "staggered": 14648, + "socialism": 14649, + "##haven": 14650, + "appointments": 14651, + "nonsense": 14652, + "prestige": 14653, + "sharma": 14654, + "haul": 14655, + "##tical": 14656, + "solidarity": 14657, + "gps": 14658, + "##ook": 14659, + "##rata": 14660, + "igor": 14661, + "pedestrian": 14662, + "##uit": 14663, + "baxter": 14664, + "tenants": 14665, + "wires": 14666, + "medication": 14667, + "unlimited": 14668, + "guiding": 14669, + "impacts": 14670, + "diabetes": 14671, + "##rama": 14672, + "sasha": 14673, + "pas": 14674, + "clive": 14675, + "extraction": 14676, + "131": 14677, + "continually": 14678, + "constraints": 14679, + "##bilities": 14680, + "sonata": 14681, + "hunted": 14682, + "sixteenth": 14683, + "chu": 14684, + "planting": 14685, + "quote": 14686, + "mayer": 14687, + "pretended": 14688, + "abs": 14689, + "spat": 14690, + "##hua": 14691, + "ceramic": 14692, + "##cci": 14693, + "curtains": 14694, + "pigs": 14695, + "pitching": 14696, + "##dad": 14697, + "latvian": 14698, + "sore": 14699, + "dayton": 14700, + "##sted": 14701, + "##qi": 14702, + "patrols": 14703, + "slice": 14704, + "playground": 14705, + "##nted": 14706, + "shone": 14707, + "stool": 14708, + "apparatus": 14709, + "inadequate": 14710, + "mates": 14711, + "treason": 14712, + "##ija": 14713, + "desires": 14714, + "##liga": 14715, + "##croft": 14716, + "somalia": 14717, + "laurent": 14718, + "mir": 14719, + "leonardo": 14720, + "oracle": 14721, + "grape": 14722, + "obliged": 14723, + "chevrolet": 14724, + "thirteenth": 14725, + "stunning": 14726, + "enthusiastic": 14727, + "##ede": 14728, + "accounted": 14729, + "concludes": 14730, + "currents": 14731, + "basil": 14732, + "##kovic": 14733, + "drought": 14734, + "##rica": 14735, + "mai": 14736, + "##aire": 14737, + "shove": 14738, + "posting": 14739, + "##shed": 14740, + "pilgrimage": 14741, + "humorous": 14742, + "packing": 14743, + "fry": 14744, + "pencil": 14745, + "wines": 14746, + "smells": 14747, + "144": 14748, + "marilyn": 14749, + "aching": 14750, + "newest": 14751, + "clung": 14752, + "bon": 14753, + "neighbours": 14754, + "sanctioned": 14755, + "##pie": 14756, + "mug": 14757, + "##stock": 14758, + "drowning": 14759, + "##mma": 14760, + "hydraulic": 14761, + "##vil": 14762, + "hiring": 14763, + "reminder": 14764, + "lilly": 14765, + "investigators": 14766, + "##ncies": 14767, + "sour": 14768, + "##eous": 14769, + "compulsory": 14770, + "packet": 14771, + "##rion": 14772, + "##graphic": 14773, + "##elle": 14774, + "cannes": 14775, + "##inate": 14776, + "depressed": 14777, + "##rit": 14778, + "heroic": 14779, + "importantly": 14780, + "theresa": 14781, + "##tled": 14782, + "conway": 14783, + "saturn": 14784, + "marginal": 14785, + "rae": 14786, + "##xia": 14787, + "corresponds": 14788, + "royce": 14789, + "pact": 14790, + "jasper": 14791, + "explosives": 14792, + "packaging": 14793, + "aluminium": 14794, + "##ttered": 14795, + "denotes": 14796, + "rhythmic": 14797, + "spans": 14798, + "assignments": 14799, + "hereditary": 14800, + "outlined": 14801, + "originating": 14802, + "sundays": 14803, + "lad": 14804, + "reissued": 14805, + "greeting": 14806, + "beatrice": 14807, + "##dic": 14808, + "pillar": 14809, + "marcos": 14810, + "plots": 14811, + "handbook": 14812, + "alcoholic": 14813, + "judiciary": 14814, + "avant": 14815, + "slides": 14816, + "extract": 14817, + "masculine": 14818, + "blur": 14819, + "##eum": 14820, + "##force": 14821, + "homage": 14822, + "trembled": 14823, + "owens": 14824, + "hymn": 14825, + "trey": 14826, + "omega": 14827, + "signaling": 14828, + "socks": 14829, + "accumulated": 14830, + "reacted": 14831, + "attic": 14832, + "theo": 14833, + "lining": 14834, + "angie": 14835, + "distraction": 14836, + "primera": 14837, + "talbot": 14838, + "##key": 14839, + "1200": 14840, + "ti": 14841, + "creativity": 14842, + "billed": 14843, + "##hey": 14844, + "deacon": 14845, + "eduardo": 14846, + "identifies": 14847, + "proposition": 14848, + "dizzy": 14849, + "gunner": 14850, + "hogan": 14851, + "##yam": 14852, + "##pping": 14853, + "##hol": 14854, + "ja": 14855, + "##chan": 14856, + "jensen": 14857, + "reconstructed": 14858, + "##berger": 14859, + "clearance": 14860, + "darius": 14861, + "##nier": 14862, + "abe": 14863, + "harlem": 14864, + "plea": 14865, + "dei": 14866, + "circled": 14867, + "emotionally": 14868, + "notation": 14869, + "fascist": 14870, + "neville": 14871, + "exceeded": 14872, + "upwards": 14873, + "viable": 14874, + "ducks": 14875, + "##fo": 14876, + "workforce": 14877, + "racer": 14878, + "limiting": 14879, + "shri": 14880, + "##lson": 14881, + "possesses": 14882, + "1600": 14883, + "kerr": 14884, + "moths": 14885, + "devastating": 14886, + "laden": 14887, + "disturbing": 14888, + "locking": 14889, + "##cture": 14890, + "gal": 14891, + "fearing": 14892, + "accreditation": 14893, + "flavor": 14894, + "aide": 14895, + "1870s": 14896, + "mountainous": 14897, + "##baum": 14898, + "melt": 14899, + "##ures": 14900, + "motel": 14901, + "texture": 14902, + "servers": 14903, + "soda": 14904, + "##mb": 14905, + "herd": 14906, + "##nium": 14907, + "erect": 14908, + "puzzled": 14909, + "hum": 14910, + "peggy": 14911, + "examinations": 14912, + "gould": 14913, + "testified": 14914, + "geoff": 14915, + "ren": 14916, + "devised": 14917, + "sacks": 14918, + "##law": 14919, + "denial": 14920, + "posters": 14921, + "grunted": 14922, + "cesar": 14923, + "tutor": 14924, + "ec": 14925, + "gerry": 14926, + "offerings": 14927, + "byrne": 14928, + "falcons": 14929, + "combinations": 14930, + "ct": 14931, + "incoming": 14932, + "pardon": 14933, + "rocking": 14934, + "26th": 14935, + "avengers": 14936, + "flared": 14937, + "mankind": 14938, + "seller": 14939, + "uttar": 14940, + "loch": 14941, + "nadia": 14942, + "stroking": 14943, + "exposing": 14944, + "##hd": 14945, + "fertile": 14946, + "ancestral": 14947, + "instituted": 14948, + "##has": 14949, + "noises": 14950, + "prophecy": 14951, + "taxation": 14952, + "eminent": 14953, + "vivid": 14954, + "pol": 14955, + "##bol": 14956, + "dart": 14957, + "indirect": 14958, + "multimedia": 14959, + "notebook": 14960, + "upside": 14961, + "displaying": 14962, + "adrenaline": 14963, + "referenced": 14964, + "geometric": 14965, + "##iving": 14966, + "progression": 14967, + "##ddy": 14968, + "blunt": 14969, + "announce": 14970, + "##far": 14971, + "implementing": 14972, + "##lav": 14973, + "aggression": 14974, + "liaison": 14975, + "cooler": 14976, + "cares": 14977, + "headache": 14978, + "plantations": 14979, + "gorge": 14980, + "dots": 14981, + "impulse": 14982, + "thickness": 14983, + "ashamed": 14984, + "averaging": 14985, + "kathy": 14986, + "obligation": 14987, + "precursor": 14988, + "137": 14989, + "fowler": 14990, + "symmetry": 14991, + "thee": 14992, + "225": 14993, + "hears": 14994, + "##rai": 14995, + "undergoing": 14996, + "ads": 14997, + "butcher": 14998, + "bowler": 14999, + "##lip": 15000, + "cigarettes": 15001, + "subscription": 15002, + "goodness": 15003, + "##ically": 15004, + "browne": 15005, + "##hos": 15006, + "##tech": 15007, + "kyoto": 15008, + "donor": 15009, + "##erty": 15010, + "damaging": 15011, + "friction": 15012, + "drifting": 15013, + "expeditions": 15014, + "hardened": 15015, + "prostitution": 15016, + "152": 15017, + "fauna": 15018, + "blankets": 15019, + "claw": 15020, + "tossing": 15021, + "snarled": 15022, + "butterflies": 15023, + "recruits": 15024, + "investigative": 15025, + "coated": 15026, + "healed": 15027, + "138": 15028, + "communal": 15029, + "hai": 15030, + "xiii": 15031, + "academics": 15032, + "boone": 15033, + "psychologist": 15034, + "restless": 15035, + "lahore": 15036, + "stephens": 15037, + "mba": 15038, + "brendan": 15039, + "foreigners": 15040, + "printer": 15041, + "##pc": 15042, + "ached": 15043, + "explode": 15044, + "27th": 15045, + "deed": 15046, + "scratched": 15047, + "dared": 15048, + "##pole": 15049, + "cardiac": 15050, + "1780": 15051, + "okinawa": 15052, + "proto": 15053, + "commando": 15054, + "compelled": 15055, + "oddly": 15056, + "electrons": 15057, + "##base": 15058, + "replica": 15059, + "thanksgiving": 15060, + "##rist": 15061, + "sheila": 15062, + "deliberate": 15063, + "stafford": 15064, + "tidal": 15065, + "representations": 15066, + "hercules": 15067, + "ou": 15068, + "##path": 15069, + "##iated": 15070, + "kidnapping": 15071, + "lenses": 15072, + "##tling": 15073, + "deficit": 15074, + "samoa": 15075, + "mouths": 15076, + "consuming": 15077, + "computational": 15078, + "maze": 15079, + "granting": 15080, + "smirk": 15081, + "razor": 15082, + "fixture": 15083, + "ideals": 15084, + "inviting": 15085, + "aiden": 15086, + "nominal": 15087, + "##vs": 15088, + "issuing": 15089, + "julio": 15090, + "pitt": 15091, + "ramsey": 15092, + "docks": 15093, + "##oss": 15094, + "exhaust": 15095, + "##owed": 15096, + "bavarian": 15097, + "draped": 15098, + "anterior": 15099, + "mating": 15100, + "ethiopian": 15101, + "explores": 15102, + "noticing": 15103, + "##nton": 15104, + "discarded": 15105, + "convenience": 15106, + "hoffman": 15107, + "endowment": 15108, + "beasts": 15109, + "cartridge": 15110, + "mormon": 15111, + "paternal": 15112, + "probe": 15113, + "sleeves": 15114, + "interfere": 15115, + "lump": 15116, + "deadline": 15117, + "##rail": 15118, + "jenks": 15119, + "bulldogs": 15120, + "scrap": 15121, + "alternating": 15122, + "justified": 15123, + "reproductive": 15124, + "nam": 15125, + "seize": 15126, + "descending": 15127, + "secretariat": 15128, + "kirby": 15129, + "coupe": 15130, + "grouped": 15131, + "smash": 15132, + "panther": 15133, + "sedan": 15134, + "tapping": 15135, + "##18": 15136, + "lola": 15137, + "cheer": 15138, + "germanic": 15139, + "unfortunate": 15140, + "##eter": 15141, + "unrelated": 15142, + "##fan": 15143, + "subordinate": 15144, + "##sdale": 15145, + "suzanne": 15146, + "advertisement": 15147, + "##ility": 15148, + "horsepower": 15149, + "##lda": 15150, + "cautiously": 15151, + "discourse": 15152, + "luigi": 15153, + "##mans": 15154, + "##fields": 15155, + "noun": 15156, + "prevalent": 15157, + "mao": 15158, + "schneider": 15159, + "everett": 15160, + "surround": 15161, + "governorate": 15162, + "kira": 15163, + "##avia": 15164, + "westward": 15165, + "##take": 15166, + "misty": 15167, + "rails": 15168, + "sustainability": 15169, + "134": 15170, + "unused": 15171, + "##rating": 15172, + "packs": 15173, + "toast": 15174, + "unwilling": 15175, + "regulate": 15176, + "thy": 15177, + "suffrage": 15178, + "nile": 15179, + "awe": 15180, + "assam": 15181, + "definitions": 15182, + "travelers": 15183, + "affordable": 15184, + "##rb": 15185, + "conferred": 15186, + "sells": 15187, + "undefeated": 15188, + "beneficial": 15189, + "torso": 15190, + "basal": 15191, + "repeating": 15192, + "remixes": 15193, + "##pass": 15194, + "bahrain": 15195, + "cables": 15196, + "fang": 15197, + "##itated": 15198, + "excavated": 15199, + "numbering": 15200, + "statutory": 15201, + "##rey": 15202, + "deluxe": 15203, + "##lian": 15204, + "forested": 15205, + "ramirez": 15206, + "derbyshire": 15207, + "zeus": 15208, + "slamming": 15209, + "transfers": 15210, + "astronomer": 15211, + "banana": 15212, + "lottery": 15213, + "berg": 15214, + "histories": 15215, + "bamboo": 15216, + "##uchi": 15217, + "resurrection": 15218, + "posterior": 15219, + "bowls": 15220, + "vaguely": 15221, + "##thi": 15222, + "thou": 15223, + "preserving": 15224, + "tensed": 15225, + "offence": 15226, + "##inas": 15227, + "meyrick": 15228, + "callum": 15229, + "ridden": 15230, + "watt": 15231, + "langdon": 15232, + "tying": 15233, + "lowland": 15234, + "snorted": 15235, + "daring": 15236, + "truman": 15237, + "##hale": 15238, + "##girl": 15239, + "aura": 15240, + "overly": 15241, + "filing": 15242, + "weighing": 15243, + "goa": 15244, + "infections": 15245, + "philanthropist": 15246, + "saunders": 15247, + "eponymous": 15248, + "##owski": 15249, + "latitude": 15250, + "perspectives": 15251, + "reviewing": 15252, + "mets": 15253, + "commandant": 15254, + "radial": 15255, + "##kha": 15256, + "flashlight": 15257, + "reliability": 15258, + "koch": 15259, + "vowels": 15260, + "amazed": 15261, + "ada": 15262, + "elaine": 15263, + "supper": 15264, + "##rth": 15265, + "##encies": 15266, + "predator": 15267, + "debated": 15268, + "soviets": 15269, + "cola": 15270, + "##boards": 15271, + "##nah": 15272, + "compartment": 15273, + "crooked": 15274, + "arbitrary": 15275, + "fourteenth": 15276, + "##ctive": 15277, + "havana": 15278, + "majors": 15279, + "steelers": 15280, + "clips": 15281, + "profitable": 15282, + "ambush": 15283, + "exited": 15284, + "packers": 15285, + "##tile": 15286, + "nude": 15287, + "cracks": 15288, + "fungi": 15289, + "##е": 15290, + "limb": 15291, + "trousers": 15292, + "josie": 15293, + "shelby": 15294, + "tens": 15295, + "frederic": 15296, + "##ος": 15297, + "definite": 15298, + "smoothly": 15299, + "constellation": 15300, + "insult": 15301, + "baton": 15302, + "discs": 15303, + "lingering": 15304, + "##nco": 15305, + "conclusions": 15306, + "lent": 15307, + "staging": 15308, + "becker": 15309, + "grandpa": 15310, + "shaky": 15311, + "##tron": 15312, + "einstein": 15313, + "obstacles": 15314, + "sk": 15315, + "adverse": 15316, + "elle": 15317, + "economically": 15318, + "##moto": 15319, + "mccartney": 15320, + "thor": 15321, + "dismissal": 15322, + "motions": 15323, + "readings": 15324, + "nostrils": 15325, + "treatise": 15326, + "##pace": 15327, + "squeezing": 15328, + "evidently": 15329, + "prolonged": 15330, + "1783": 15331, + "venezuelan": 15332, + "je": 15333, + "marguerite": 15334, + "beirut": 15335, + "takeover": 15336, + "shareholders": 15337, + "##vent": 15338, + "denise": 15339, + "digit": 15340, + "airplay": 15341, + "norse": 15342, + "##bbling": 15343, + "imaginary": 15344, + "pills": 15345, + "hubert": 15346, + "blaze": 15347, + "vacated": 15348, + "eliminating": 15349, + "##ello": 15350, + "vine": 15351, + "mansfield": 15352, + "##tty": 15353, + "retrospective": 15354, + "barrow": 15355, + "borne": 15356, + "clutch": 15357, + "bail": 15358, + "forensic": 15359, + "weaving": 15360, + "##nett": 15361, + "##witz": 15362, + "desktop": 15363, + "citadel": 15364, + "promotions": 15365, + "worrying": 15366, + "dorset": 15367, + "ieee": 15368, + "subdivided": 15369, + "##iating": 15370, + "manned": 15371, + "expeditionary": 15372, + "pickup": 15373, + "synod": 15374, + "chuckle": 15375, + "185": 15376, + "barney": 15377, + "##rz": 15378, + "##ffin": 15379, + "functionality": 15380, + "karachi": 15381, + "litigation": 15382, + "meanings": 15383, + "uc": 15384, + "lick": 15385, + "turbo": 15386, + "anders": 15387, + "##ffed": 15388, + "execute": 15389, + "curl": 15390, + "oppose": 15391, + "ankles": 15392, + "typhoon": 15393, + "##د": 15394, + "##ache": 15395, + "##asia": 15396, + "linguistics": 15397, + "compassion": 15398, + "pressures": 15399, + "grazing": 15400, + "perfection": 15401, + "##iting": 15402, + "immunity": 15403, + "monopoly": 15404, + "muddy": 15405, + "backgrounds": 15406, + "136": 15407, + "namibia": 15408, + "francesca": 15409, + "monitors": 15410, + "attracting": 15411, + "stunt": 15412, + "tuition": 15413, + "##ии": 15414, + "vegetable": 15415, + "##mates": 15416, + "##quent": 15417, + "mgm": 15418, + "jen": 15419, + "complexes": 15420, + "forts": 15421, + "##ond": 15422, + "cellar": 15423, + "bites": 15424, + "seventeenth": 15425, + "royals": 15426, + "flemish": 15427, + "failures": 15428, + "mast": 15429, + "charities": 15430, + "##cular": 15431, + "peruvian": 15432, + "capitals": 15433, + "macmillan": 15434, + "ipswich": 15435, + "outward": 15436, + "frigate": 15437, + "postgraduate": 15438, + "folds": 15439, + "employing": 15440, + "##ouse": 15441, + "concurrently": 15442, + "fiery": 15443, + "##tai": 15444, + "contingent": 15445, + "nightmares": 15446, + "monumental": 15447, + "nicaragua": 15448, + "##kowski": 15449, + "lizard": 15450, + "mal": 15451, + "fielding": 15452, + "gig": 15453, + "reject": 15454, + "##pad": 15455, + "harding": 15456, + "##ipe": 15457, + "coastline": 15458, + "##cin": 15459, + "##nos": 15460, + "beethoven": 15461, + "humphrey": 15462, + "innovations": 15463, + "##tam": 15464, + "##nge": 15465, + "norris": 15466, + "doris": 15467, + "solicitor": 15468, + "huang": 15469, + "obey": 15470, + "141": 15471, + "##lc": 15472, + "niagara": 15473, + "##tton": 15474, + "shelves": 15475, + "aug": 15476, + "bourbon": 15477, + "curry": 15478, + "nightclub": 15479, + "specifications": 15480, + "hilton": 15481, + "##ndo": 15482, + "centennial": 15483, + "dispersed": 15484, + "worm": 15485, + "neglected": 15486, + "briggs": 15487, + "sm": 15488, + "font": 15489, + "kuala": 15490, + "uneasy": 15491, + "plc": 15492, + "##nstein": 15493, + "##bound": 15494, + "##aking": 15495, + "##burgh": 15496, + "awaiting": 15497, + "pronunciation": 15498, + "##bbed": 15499, + "##quest": 15500, + "eh": 15501, + "optimal": 15502, + "zhu": 15503, + "raped": 15504, + "greens": 15505, + "presided": 15506, + "brenda": 15507, + "worries": 15508, + "##life": 15509, + "venetian": 15510, + "marxist": 15511, + "turnout": 15512, + "##lius": 15513, + "refined": 15514, + "braced": 15515, + "sins": 15516, + "grasped": 15517, + "sunderland": 15518, + "nickel": 15519, + "speculated": 15520, + "lowell": 15521, + "cyrillic": 15522, + "communism": 15523, + "fundraising": 15524, + "resembling": 15525, + "colonists": 15526, + "mutant": 15527, + "freddie": 15528, + "usc": 15529, + "##mos": 15530, + "gratitude": 15531, + "##run": 15532, + "mural": 15533, + "##lous": 15534, + "chemist": 15535, + "wi": 15536, + "reminds": 15537, + "28th": 15538, + "steals": 15539, + "tess": 15540, + "pietro": 15541, + "##ingen": 15542, + "promoter": 15543, + "ri": 15544, + "microphone": 15545, + "honoured": 15546, + "rai": 15547, + "sant": 15548, + "##qui": 15549, + "feather": 15550, + "##nson": 15551, + "burlington": 15552, + "kurdish": 15553, + "terrorists": 15554, + "deborah": 15555, + "sickness": 15556, + "##wed": 15557, + "##eet": 15558, + "hazard": 15559, + "irritated": 15560, + "desperation": 15561, + "veil": 15562, + "clarity": 15563, + "##rik": 15564, + "jewels": 15565, + "xv": 15566, + "##gged": 15567, + "##ows": 15568, + "##cup": 15569, + "berkshire": 15570, + "unfair": 15571, + "mysteries": 15572, + "orchid": 15573, + "winced": 15574, + "exhaustion": 15575, + "renovations": 15576, + "stranded": 15577, + "obe": 15578, + "infinity": 15579, + "##nies": 15580, + "adapt": 15581, + "redevelopment": 15582, + "thanked": 15583, + "registry": 15584, + "olga": 15585, + "domingo": 15586, + "noir": 15587, + "tudor": 15588, + "ole": 15589, + "##atus": 15590, + "commenting": 15591, + "behaviors": 15592, + "##ais": 15593, + "crisp": 15594, + "pauline": 15595, + "probable": 15596, + "stirling": 15597, + "wigan": 15598, + "##bian": 15599, + "paralympics": 15600, + "panting": 15601, + "surpassed": 15602, + "##rew": 15603, + "luca": 15604, + "barred": 15605, + "pony": 15606, + "famed": 15607, + "##sters": 15608, + "cassandra": 15609, + "waiter": 15610, + "carolyn": 15611, + "exported": 15612, + "##orted": 15613, + "andres": 15614, + "destructive": 15615, + "deeds": 15616, + "jonah": 15617, + "castles": 15618, + "vacancy": 15619, + "suv": 15620, + "##glass": 15621, + "1788": 15622, + "orchard": 15623, + "yep": 15624, + "famine": 15625, + "belarusian": 15626, + "sprang": 15627, + "##forth": 15628, + "skinny": 15629, + "##mis": 15630, + "administrators": 15631, + "rotterdam": 15632, + "zambia": 15633, + "zhao": 15634, + "boiler": 15635, + "discoveries": 15636, + "##ride": 15637, + "##physics": 15638, + "lucius": 15639, + "disappointing": 15640, + "outreach": 15641, + "spoon": 15642, + "##frame": 15643, + "qualifications": 15644, + "unanimously": 15645, + "enjoys": 15646, + "regency": 15647, + "##iidae": 15648, + "stade": 15649, + "realism": 15650, + "veterinary": 15651, + "rodgers": 15652, + "dump": 15653, + "alain": 15654, + "chestnut": 15655, + "castile": 15656, + "censorship": 15657, + "rumble": 15658, + "gibbs": 15659, + "##itor": 15660, + "communion": 15661, + "reggae": 15662, + "inactivated": 15663, + "logs": 15664, + "loads": 15665, + "##houses": 15666, + "homosexual": 15667, + "##iano": 15668, + "ale": 15669, + "informs": 15670, + "##cas": 15671, + "phrases": 15672, + "plaster": 15673, + "linebacker": 15674, + "ambrose": 15675, + "kaiser": 15676, + "fascinated": 15677, + "850": 15678, + "limerick": 15679, + "recruitment": 15680, + "forge": 15681, + "mastered": 15682, + "##nding": 15683, + "leinster": 15684, + "rooted": 15685, + "threaten": 15686, + "##strom": 15687, + "borneo": 15688, + "##hes": 15689, + "suggestions": 15690, + "scholarships": 15691, + "propeller": 15692, + "documentaries": 15693, + "patronage": 15694, + "coats": 15695, + "constructing": 15696, + "invest": 15697, + "neurons": 15698, + "comet": 15699, + "entirety": 15700, + "shouts": 15701, + "identities": 15702, + "annoying": 15703, + "unchanged": 15704, + "wary": 15705, + "##antly": 15706, + "##ogy": 15707, + "neat": 15708, + "oversight": 15709, + "##kos": 15710, + "phillies": 15711, + "replay": 15712, + "constance": 15713, + "##kka": 15714, + "incarnation": 15715, + "humble": 15716, + "skies": 15717, + "minus": 15718, + "##acy": 15719, + "smithsonian": 15720, + "##chel": 15721, + "guerrilla": 15722, + "jar": 15723, + "cadets": 15724, + "##plate": 15725, + "surplus": 15726, + "audit": 15727, + "##aru": 15728, + "cracking": 15729, + "joanna": 15730, + "louisa": 15731, + "pacing": 15732, + "##lights": 15733, + "intentionally": 15734, + "##iri": 15735, + "diner": 15736, + "nwa": 15737, + "imprint": 15738, + "australians": 15739, + "tong": 15740, + "unprecedented": 15741, + "bunker": 15742, + "naive": 15743, + "specialists": 15744, + "ark": 15745, + "nichols": 15746, + "railing": 15747, + "leaked": 15748, + "pedal": 15749, + "##uka": 15750, + "shrub": 15751, + "longing": 15752, + "roofs": 15753, + "v8": 15754, + "captains": 15755, + "neural": 15756, + "tuned": 15757, + "##ntal": 15758, + "##jet": 15759, + "emission": 15760, + "medina": 15761, + "frantic": 15762, + "codex": 15763, + "definitive": 15764, + "sid": 15765, + "abolition": 15766, + "intensified": 15767, + "stocks": 15768, + "enrique": 15769, + "sustain": 15770, + "genoa": 15771, + "oxide": 15772, + "##written": 15773, + "clues": 15774, + "cha": 15775, + "##gers": 15776, + "tributaries": 15777, + "fragment": 15778, + "venom": 15779, + "##rity": 15780, + "##ente": 15781, + "##sca": 15782, + "muffled": 15783, + "vain": 15784, + "sire": 15785, + "laos": 15786, + "##ingly": 15787, + "##hana": 15788, + "hastily": 15789, + "snapping": 15790, + "surfaced": 15791, + "sentiment": 15792, + "motive": 15793, + "##oft": 15794, + "contests": 15795, + "approximate": 15796, + "mesa": 15797, + "luckily": 15798, + "dinosaur": 15799, + "exchanges": 15800, + "propelled": 15801, + "accord": 15802, + "bourne": 15803, + "relieve": 15804, + "tow": 15805, + "masks": 15806, + "offended": 15807, + "##ues": 15808, + "cynthia": 15809, + "##mmer": 15810, + "rains": 15811, + "bartender": 15812, + "zinc": 15813, + "reviewers": 15814, + "lois": 15815, + "##sai": 15816, + "legged": 15817, + "arrogant": 15818, + "rafe": 15819, + "rosie": 15820, + "comprise": 15821, + "handicap": 15822, + "blockade": 15823, + "inlet": 15824, + "lagoon": 15825, + "copied": 15826, + "drilling": 15827, + "shelley": 15828, + "petals": 15829, + "##inian": 15830, + "mandarin": 15831, + "obsolete": 15832, + "##inated": 15833, + "onward": 15834, + "arguably": 15835, + "productivity": 15836, + "cindy": 15837, + "praising": 15838, + "seldom": 15839, + "busch": 15840, + "discusses": 15841, + "raleigh": 15842, + "shortage": 15843, + "ranged": 15844, + "stanton": 15845, + "encouragement": 15846, + "firstly": 15847, + "conceded": 15848, + "overs": 15849, + "temporal": 15850, + "##uke": 15851, + "cbe": 15852, + "##bos": 15853, + "woo": 15854, + "certainty": 15855, + "pumps": 15856, + "##pton": 15857, + "stalked": 15858, + "##uli": 15859, + "lizzie": 15860, + "periodic": 15861, + "thieves": 15862, + "weaker": 15863, + "##night": 15864, + "gases": 15865, + "shoving": 15866, + "chooses": 15867, + "wc": 15868, + "##chemical": 15869, + "prompting": 15870, + "weights": 15871, + "##kill": 15872, + "robust": 15873, + "flanked": 15874, + "sticky": 15875, + "hu": 15876, + "tuberculosis": 15877, + "##eb": 15878, + "##eal": 15879, + "christchurch": 15880, + "resembled": 15881, + "wallet": 15882, + "reese": 15883, + "inappropriate": 15884, + "pictured": 15885, + "distract": 15886, + "fixing": 15887, + "fiddle": 15888, + "giggled": 15889, + "burger": 15890, + "heirs": 15891, + "hairy": 15892, + "mechanic": 15893, + "torque": 15894, + "apache": 15895, + "obsessed": 15896, + "chiefly": 15897, + "cheng": 15898, + "logging": 15899, + "##tag": 15900, + "extracted": 15901, + "meaningful": 15902, + "numb": 15903, + "##vsky": 15904, + "gloucestershire": 15905, + "reminding": 15906, + "##bay": 15907, + "unite": 15908, + "##lit": 15909, + "breeds": 15910, + "diminished": 15911, + "clown": 15912, + "glove": 15913, + "1860s": 15914, + "##ن": 15915, + "##ug": 15916, + "archibald": 15917, + "focal": 15918, + "freelance": 15919, + "sliced": 15920, + "depiction": 15921, + "##yk": 15922, + "organism": 15923, + "switches": 15924, + "sights": 15925, + "stray": 15926, + "crawling": 15927, + "##ril": 15928, + "lever": 15929, + "leningrad": 15930, + "interpretations": 15931, + "loops": 15932, + "anytime": 15933, + "reel": 15934, + "alicia": 15935, + "delighted": 15936, + "##ech": 15937, + "inhaled": 15938, + "xiv": 15939, + "suitcase": 15940, + "bernie": 15941, + "vega": 15942, + "licenses": 15943, + "northampton": 15944, + "exclusion": 15945, + "induction": 15946, + "monasteries": 15947, + "racecourse": 15948, + "homosexuality": 15949, + "##right": 15950, + "##sfield": 15951, + "##rky": 15952, + "dimitri": 15953, + "michele": 15954, + "alternatives": 15955, + "ions": 15956, + "commentators": 15957, + "genuinely": 15958, + "objected": 15959, + "pork": 15960, + "hospitality": 15961, + "fencing": 15962, + "stephan": 15963, + "warships": 15964, + "peripheral": 15965, + "wit": 15966, + "drunken": 15967, + "wrinkled": 15968, + "quentin": 15969, + "spends": 15970, + "departing": 15971, + "chung": 15972, + "numerical": 15973, + "spokesperson": 15974, + "##zone": 15975, + "johannesburg": 15976, + "caliber": 15977, + "killers": 15978, + "##udge": 15979, + "assumes": 15980, + "neatly": 15981, + "demographic": 15982, + "abigail": 15983, + "bloc": 15984, + "##vel": 15985, + "mounting": 15986, + "##lain": 15987, + "bentley": 15988, + "slightest": 15989, + "xu": 15990, + "recipients": 15991, + "##jk": 15992, + "merlin": 15993, + "##writer": 15994, + "seniors": 15995, + "prisons": 15996, + "blinking": 15997, + "hindwings": 15998, + "flickered": 15999, + "kappa": 16000, + "##hel": 16001, + "80s": 16002, + "strengthening": 16003, + "appealing": 16004, + "brewing": 16005, + "gypsy": 16006, + "mali": 16007, + "lashes": 16008, + "hulk": 16009, + "unpleasant": 16010, + "harassment": 16011, + "bio": 16012, + "treaties": 16013, + "predict": 16014, + "instrumentation": 16015, + "pulp": 16016, + "troupe": 16017, + "boiling": 16018, + "mantle": 16019, + "##ffe": 16020, + "ins": 16021, + "##vn": 16022, + "dividing": 16023, + "handles": 16024, + "verbs": 16025, + "##onal": 16026, + "coconut": 16027, + "senegal": 16028, + "340": 16029, + "thorough": 16030, + "gum": 16031, + "momentarily": 16032, + "##sto": 16033, + "cocaine": 16034, + "panicked": 16035, + "destined": 16036, + "##turing": 16037, + "teatro": 16038, + "denying": 16039, + "weary": 16040, + "captained": 16041, + "mans": 16042, + "##hawks": 16043, + "##code": 16044, + "wakefield": 16045, + "bollywood": 16046, + "thankfully": 16047, + "##16": 16048, + "cyril": 16049, + "##wu": 16050, + "amendments": 16051, + "##bahn": 16052, + "consultation": 16053, + "stud": 16054, + "reflections": 16055, + "kindness": 16056, + "1787": 16057, + "internally": 16058, + "##ovo": 16059, + "tex": 16060, + "mosaic": 16061, + "distribute": 16062, + "paddy": 16063, + "seeming": 16064, + "143": 16065, + "##hic": 16066, + "piers": 16067, + "##15": 16068, + "##mura": 16069, + "##verse": 16070, + "popularly": 16071, + "winger": 16072, + "kang": 16073, + "sentinel": 16074, + "mccoy": 16075, + "##anza": 16076, + "covenant": 16077, + "##bag": 16078, + "verge": 16079, + "fireworks": 16080, + "suppress": 16081, + "thrilled": 16082, + "dominate": 16083, + "##jar": 16084, + "swansea": 16085, + "##60": 16086, + "142": 16087, + "reconciliation": 16088, + "##ndi": 16089, + "stiffened": 16090, + "cue": 16091, + "dorian": 16092, + "##uf": 16093, + "damascus": 16094, + "amor": 16095, + "ida": 16096, + "foremost": 16097, + "##aga": 16098, + "porsche": 16099, + "unseen": 16100, + "dir": 16101, + "##had": 16102, + "##azi": 16103, + "stony": 16104, + "lexi": 16105, + "melodies": 16106, + "##nko": 16107, + "angular": 16108, + "integer": 16109, + "podcast": 16110, + "ants": 16111, + "inherent": 16112, + "jaws": 16113, + "justify": 16114, + "persona": 16115, + "##olved": 16116, + "josephine": 16117, + "##nr": 16118, + "##ressed": 16119, + "customary": 16120, + "flashes": 16121, + "gala": 16122, + "cyrus": 16123, + "glaring": 16124, + "backyard": 16125, + "ariel": 16126, + "physiology": 16127, + "greenland": 16128, + "html": 16129, + "stir": 16130, + "avon": 16131, + "atletico": 16132, + "finch": 16133, + "methodology": 16134, + "ked": 16135, + "##lent": 16136, + "mas": 16137, + "catholicism": 16138, + "townsend": 16139, + "branding": 16140, + "quincy": 16141, + "fits": 16142, + "containers": 16143, + "1777": 16144, + "ashore": 16145, + "aragon": 16146, + "##19": 16147, + "forearm": 16148, + "poisoning": 16149, + "##sd": 16150, + "adopting": 16151, + "conquer": 16152, + "grinding": 16153, + "amnesty": 16154, + "keller": 16155, + "finances": 16156, + "evaluate": 16157, + "forged": 16158, + "lankan": 16159, + "instincts": 16160, + "##uto": 16161, + "guam": 16162, + "bosnian": 16163, + "photographed": 16164, + "workplace": 16165, + "desirable": 16166, + "protector": 16167, + "##dog": 16168, + "allocation": 16169, + "intently": 16170, + "encourages": 16171, + "willy": 16172, + "##sten": 16173, + "bodyguard": 16174, + "electro": 16175, + "brighter": 16176, + "##ν": 16177, + "bihar": 16178, + "##chev": 16179, + "lasts": 16180, + "opener": 16181, + "amphibious": 16182, + "sal": 16183, + "verde": 16184, + "arte": 16185, + "##cope": 16186, + "captivity": 16187, + "vocabulary": 16188, + "yields": 16189, + "##tted": 16190, + "agreeing": 16191, + "desmond": 16192, + "pioneered": 16193, + "##chus": 16194, + "strap": 16195, + "campaigned": 16196, + "railroads": 16197, + "##ович": 16198, + "emblem": 16199, + "##dre": 16200, + "stormed": 16201, + "501": 16202, + "##ulous": 16203, + "marijuana": 16204, + "northumberland": 16205, + "##gn": 16206, + "##nath": 16207, + "bowen": 16208, + "landmarks": 16209, + "beaumont": 16210, + "##qua": 16211, + "danube": 16212, + "##bler": 16213, + "attorneys": 16214, + "th": 16215, + "ge": 16216, + "flyers": 16217, + "critique": 16218, + "villains": 16219, + "cass": 16220, + "mutation": 16221, + "acc": 16222, + "##0s": 16223, + "colombo": 16224, + "mckay": 16225, + "motif": 16226, + "sampling": 16227, + "concluding": 16228, + "syndicate": 16229, + "##rell": 16230, + "neon": 16231, + "stables": 16232, + "ds": 16233, + "warnings": 16234, + "clint": 16235, + "mourning": 16236, + "wilkinson": 16237, + "##tated": 16238, + "merrill": 16239, + "leopard": 16240, + "evenings": 16241, + "exhaled": 16242, + "emil": 16243, + "sonia": 16244, + "ezra": 16245, + "discrete": 16246, + "stove": 16247, + "farrell": 16248, + "fifteenth": 16249, + "prescribed": 16250, + "superhero": 16251, + "##rier": 16252, + "worms": 16253, + "helm": 16254, + "wren": 16255, + "##duction": 16256, + "##hc": 16257, + "expo": 16258, + "##rator": 16259, + "hq": 16260, + "unfamiliar": 16261, + "antony": 16262, + "prevents": 16263, + "acceleration": 16264, + "fiercely": 16265, + "mari": 16266, + "painfully": 16267, + "calculations": 16268, + "cheaper": 16269, + "ign": 16270, + "clifton": 16271, + "irvine": 16272, + "davenport": 16273, + "mozambique": 16274, + "##np": 16275, + "pierced": 16276, + "##evich": 16277, + "wonders": 16278, + "##wig": 16279, + "##cate": 16280, + "##iling": 16281, + "crusade": 16282, + "ware": 16283, + "##uel": 16284, + "enzymes": 16285, + "reasonably": 16286, + "mls": 16287, + "##coe": 16288, + "mater": 16289, + "ambition": 16290, + "bunny": 16291, + "eliot": 16292, + "kernel": 16293, + "##fin": 16294, + "asphalt": 16295, + "headmaster": 16296, + "torah": 16297, + "aden": 16298, + "lush": 16299, + "pins": 16300, + "waived": 16301, + "##care": 16302, + "##yas": 16303, + "joao": 16304, + "substrate": 16305, + "enforce": 16306, + "##grad": 16307, + "##ules": 16308, + "alvarez": 16309, + "selections": 16310, + "epidemic": 16311, + "tempted": 16312, + "##bit": 16313, + "bremen": 16314, + "translates": 16315, + "ensured": 16316, + "waterfront": 16317, + "29th": 16318, + "forrest": 16319, + "manny": 16320, + "malone": 16321, + "kramer": 16322, + "reigning": 16323, + "cookies": 16324, + "simpler": 16325, + "absorption": 16326, + "205": 16327, + "engraved": 16328, + "##ffy": 16329, + "evaluated": 16330, + "1778": 16331, + "haze": 16332, + "146": 16333, + "comforting": 16334, + "crossover": 16335, + "##abe": 16336, + "thorn": 16337, + "##rift": 16338, + "##imo": 16339, + "##pop": 16340, + "suppression": 16341, + "fatigue": 16342, + "cutter": 16343, + "##tr": 16344, + "201": 16345, + "wurttemberg": 16346, + "##orf": 16347, + "enforced": 16348, + "hovering": 16349, + "proprietary": 16350, + "gb": 16351, + "samurai": 16352, + "syllable": 16353, + "ascent": 16354, + "lacey": 16355, + "tick": 16356, + "lars": 16357, + "tractor": 16358, + "merchandise": 16359, + "rep": 16360, + "bouncing": 16361, + "defendants": 16362, + "##yre": 16363, + "huntington": 16364, + "##ground": 16365, + "##oko": 16366, + "standardized": 16367, + "##hor": 16368, + "##hima": 16369, + "assassinated": 16370, + "nu": 16371, + "predecessors": 16372, + "rainy": 16373, + "liar": 16374, + "assurance": 16375, + "lyrical": 16376, + "##uga": 16377, + "secondly": 16378, + "flattened": 16379, + "ios": 16380, + "parameter": 16381, + "undercover": 16382, + "##mity": 16383, + "bordeaux": 16384, + "punish": 16385, + "ridges": 16386, + "markers": 16387, + "exodus": 16388, + "inactive": 16389, + "hesitate": 16390, + "debbie": 16391, + "nyc": 16392, + "pledge": 16393, + "savoy": 16394, + "nagar": 16395, + "offset": 16396, + "organist": 16397, + "##tium": 16398, + "hesse": 16399, + "marin": 16400, + "converting": 16401, + "##iver": 16402, + "diagram": 16403, + "propulsion": 16404, + "pu": 16405, + "validity": 16406, + "reverted": 16407, + "supportive": 16408, + "##dc": 16409, + "ministries": 16410, + "clans": 16411, + "responds": 16412, + "proclamation": 16413, + "##inae": 16414, + "##ø": 16415, + "##rea": 16416, + "ein": 16417, + "pleading": 16418, + "patriot": 16419, + "sf": 16420, + "birch": 16421, + "islanders": 16422, + "strauss": 16423, + "hates": 16424, + "##dh": 16425, + "brandenburg": 16426, + "concession": 16427, + "rd": 16428, + "##ob": 16429, + "1900s": 16430, + "killings": 16431, + "textbook": 16432, + "antiquity": 16433, + "cinematography": 16434, + "wharf": 16435, + "embarrassing": 16436, + "setup": 16437, + "creed": 16438, + "farmland": 16439, + "inequality": 16440, + "centred": 16441, + "signatures": 16442, + "fallon": 16443, + "370": 16444, + "##ingham": 16445, + "##uts": 16446, + "ceylon": 16447, + "gazing": 16448, + "directive": 16449, + "laurie": 16450, + "##tern": 16451, + "globally": 16452, + "##uated": 16453, + "##dent": 16454, + "allah": 16455, + "excavation": 16456, + "threads": 16457, + "##cross": 16458, + "148": 16459, + "frantically": 16460, + "icc": 16461, + "utilize": 16462, + "determines": 16463, + "respiratory": 16464, + "thoughtful": 16465, + "receptions": 16466, + "##dicate": 16467, + "merging": 16468, + "chandra": 16469, + "seine": 16470, + "147": 16471, + "builders": 16472, + "builds": 16473, + "diagnostic": 16474, + "dev": 16475, + "visibility": 16476, + "goddamn": 16477, + "analyses": 16478, + "dhaka": 16479, + "cho": 16480, + "proves": 16481, + "chancel": 16482, + "concurrent": 16483, + "curiously": 16484, + "canadians": 16485, + "pumped": 16486, + "restoring": 16487, + "1850s": 16488, + "turtles": 16489, + "jaguar": 16490, + "sinister": 16491, + "spinal": 16492, + "traction": 16493, + "declan": 16494, + "vows": 16495, + "1784": 16496, + "glowed": 16497, + "capitalism": 16498, + "swirling": 16499, + "install": 16500, + "universidad": 16501, + "##lder": 16502, + "##oat": 16503, + "soloist": 16504, + "##genic": 16505, + "##oor": 16506, + "coincidence": 16507, + "beginnings": 16508, + "nissan": 16509, + "dip": 16510, + "resorts": 16511, + "caucasus": 16512, + "combustion": 16513, + "infectious": 16514, + "##eno": 16515, + "pigeon": 16516, + "serpent": 16517, + "##itating": 16518, + "conclude": 16519, + "masked": 16520, + "salad": 16521, + "jew": 16522, + "##gr": 16523, + "surreal": 16524, + "toni": 16525, + "##wc": 16526, + "harmonica": 16527, + "151": 16528, + "##gins": 16529, + "##etic": 16530, + "##coat": 16531, + "fishermen": 16532, + "intending": 16533, + "bravery": 16534, + "##wave": 16535, + "klaus": 16536, + "titan": 16537, + "wembley": 16538, + "taiwanese": 16539, + "ransom": 16540, + "40th": 16541, + "incorrect": 16542, + "hussein": 16543, + "eyelids": 16544, + "jp": 16545, + "cooke": 16546, + "dramas": 16547, + "utilities": 16548, + "##etta": 16549, + "##print": 16550, + "eisenhower": 16551, + "principally": 16552, + "granada": 16553, + "lana": 16554, + "##rak": 16555, + "openings": 16556, + "concord": 16557, + "##bl": 16558, + "bethany": 16559, + "connie": 16560, + "morality": 16561, + "sega": 16562, + "##mons": 16563, + "##nard": 16564, + "earnings": 16565, + "##kara": 16566, + "##cine": 16567, + "wii": 16568, + "communes": 16569, + "##rel": 16570, + "coma": 16571, + "composing": 16572, + "softened": 16573, + "severed": 16574, + "grapes": 16575, + "##17": 16576, + "nguyen": 16577, + "analyzed": 16578, + "warlord": 16579, + "hubbard": 16580, + "heavenly": 16581, + "behave": 16582, + "slovenian": 16583, + "##hit": 16584, + "##ony": 16585, + "hailed": 16586, + "filmmakers": 16587, + "trance": 16588, + "caldwell": 16589, + "skye": 16590, + "unrest": 16591, + "coward": 16592, + "likelihood": 16593, + "##aging": 16594, + "bern": 16595, + "sci": 16596, + "taliban": 16597, + "honolulu": 16598, + "propose": 16599, + "##wang": 16600, + "1700": 16601, + "browser": 16602, + "imagining": 16603, + "cobra": 16604, + "contributes": 16605, + "dukes": 16606, + "instinctively": 16607, + "conan": 16608, + "violinist": 16609, + "##ores": 16610, + "accessories": 16611, + "gradual": 16612, + "##amp": 16613, + "quotes": 16614, + "sioux": 16615, + "##dating": 16616, + "undertake": 16617, + "intercepted": 16618, + "sparkling": 16619, + "compressed": 16620, + "139": 16621, + "fungus": 16622, + "tombs": 16623, + "haley": 16624, + "imposing": 16625, + "rests": 16626, + "degradation": 16627, + "lincolnshire": 16628, + "retailers": 16629, + "wetlands": 16630, + "tulsa": 16631, + "distributor": 16632, + "dungeon": 16633, + "nun": 16634, + "greenhouse": 16635, + "convey": 16636, + "atlantis": 16637, + "aft": 16638, + "exits": 16639, + "oman": 16640, + "dresser": 16641, + "lyons": 16642, + "##sti": 16643, + "joking": 16644, + "eddy": 16645, + "judgement": 16646, + "omitted": 16647, + "digits": 16648, + "##cts": 16649, + "##game": 16650, + "juniors": 16651, + "##rae": 16652, + "cents": 16653, + "stricken": 16654, + "une": 16655, + "##ngo": 16656, + "wizards": 16657, + "weir": 16658, + "breton": 16659, + "nan": 16660, + "technician": 16661, + "fibers": 16662, + "liking": 16663, + "royalty": 16664, + "##cca": 16665, + "154": 16666, + "persia": 16667, + "terribly": 16668, + "magician": 16669, + "##rable": 16670, + "##unt": 16671, + "vance": 16672, + "cafeteria": 16673, + "booker": 16674, + "camille": 16675, + "warmer": 16676, + "##static": 16677, + "consume": 16678, + "cavern": 16679, + "gaps": 16680, + "compass": 16681, + "contemporaries": 16682, + "foyer": 16683, + "soothing": 16684, + "graveyard": 16685, + "maj": 16686, + "plunged": 16687, + "blush": 16688, + "##wear": 16689, + "cascade": 16690, + "demonstrates": 16691, + "ordinance": 16692, + "##nov": 16693, + "boyle": 16694, + "##lana": 16695, + "rockefeller": 16696, + "shaken": 16697, + "banjo": 16698, + "izzy": 16699, + "##ense": 16700, + "breathless": 16701, + "vines": 16702, + "##32": 16703, + "##eman": 16704, + "alterations": 16705, + "chromosome": 16706, + "dwellings": 16707, + "feudal": 16708, + "mole": 16709, + "153": 16710, + "catalonia": 16711, + "relics": 16712, + "tenant": 16713, + "mandated": 16714, + "##fm": 16715, + "fridge": 16716, + "hats": 16717, + "honesty": 16718, + "patented": 16719, + "raul": 16720, + "heap": 16721, + "cruisers": 16722, + "accusing": 16723, + "enlightenment": 16724, + "infants": 16725, + "wherein": 16726, + "chatham": 16727, + "contractors": 16728, + "zen": 16729, + "affinity": 16730, + "hc": 16731, + "osborne": 16732, + "piston": 16733, + "156": 16734, + "traps": 16735, + "maturity": 16736, + "##rana": 16737, + "lagos": 16738, + "##zal": 16739, + "peering": 16740, + "##nay": 16741, + "attendant": 16742, + "dealers": 16743, + "protocols": 16744, + "subset": 16745, + "prospects": 16746, + "biographical": 16747, + "##cre": 16748, + "artery": 16749, + "##zers": 16750, + "insignia": 16751, + "nuns": 16752, + "endured": 16753, + "##eration": 16754, + "recommend": 16755, + "schwartz": 16756, + "serbs": 16757, + "berger": 16758, + "cromwell": 16759, + "crossroads": 16760, + "##ctor": 16761, + "enduring": 16762, + "clasped": 16763, + "grounded": 16764, + "##bine": 16765, + "marseille": 16766, + "twitched": 16767, + "abel": 16768, + "choke": 16769, + "https": 16770, + "catalyst": 16771, + "moldova": 16772, + "italians": 16773, + "##tist": 16774, + "disastrous": 16775, + "wee": 16776, + "##oured": 16777, + "##nti": 16778, + "wwf": 16779, + "nope": 16780, + "##piration": 16781, + "##asa": 16782, + "expresses": 16783, + "thumbs": 16784, + "167": 16785, + "##nza": 16786, + "coca": 16787, + "1781": 16788, + "cheating": 16789, + "##ption": 16790, + "skipped": 16791, + "sensory": 16792, + "heidelberg": 16793, + "spies": 16794, + "satan": 16795, + "dangers": 16796, + "semifinal": 16797, + "202": 16798, + "bohemia": 16799, + "whitish": 16800, + "confusing": 16801, + "shipbuilding": 16802, + "relies": 16803, + "surgeons": 16804, + "landings": 16805, + "ravi": 16806, + "baku": 16807, + "moor": 16808, + "suffix": 16809, + "alejandro": 16810, + "##yana": 16811, + "litre": 16812, + "upheld": 16813, + "##unk": 16814, + "rajasthan": 16815, + "##rek": 16816, + "coaster": 16817, + "insists": 16818, + "posture": 16819, + "scenarios": 16820, + "etienne": 16821, + "favoured": 16822, + "appoint": 16823, + "transgender": 16824, + "elephants": 16825, + "poked": 16826, + "greenwood": 16827, + "defences": 16828, + "fulfilled": 16829, + "militant": 16830, + "somali": 16831, + "1758": 16832, + "chalk": 16833, + "potent": 16834, + "##ucci": 16835, + "migrants": 16836, + "wink": 16837, + "assistants": 16838, + "nos": 16839, + "restriction": 16840, + "activism": 16841, + "niger": 16842, + "##ario": 16843, + "colon": 16844, + "shaun": 16845, + "##sat": 16846, + "daphne": 16847, + "##erated": 16848, + "swam": 16849, + "congregations": 16850, + "reprise": 16851, + "considerations": 16852, + "magnet": 16853, + "playable": 16854, + "xvi": 16855, + "##р": 16856, + "overthrow": 16857, + "tobias": 16858, + "knob": 16859, + "chavez": 16860, + "coding": 16861, + "##mers": 16862, + "propped": 16863, + "katrina": 16864, + "orient": 16865, + "newcomer": 16866, + "##suke": 16867, + "temperate": 16868, + "##pool": 16869, + "farmhouse": 16870, + "interrogation": 16871, + "##vd": 16872, + "committing": 16873, + "##vert": 16874, + "forthcoming": 16875, + "strawberry": 16876, + "joaquin": 16877, + "macau": 16878, + "ponds": 16879, + "shocking": 16880, + "siberia": 16881, + "##cellular": 16882, + "chant": 16883, + "contributors": 16884, + "##nant": 16885, + "##ologists": 16886, + "sped": 16887, + "absorb": 16888, + "hail": 16889, + "1782": 16890, + "spared": 16891, + "##hore": 16892, + "barbados": 16893, + "karate": 16894, + "opus": 16895, + "originates": 16896, + "saul": 16897, + "##xie": 16898, + "evergreen": 16899, + "leaped": 16900, + "##rock": 16901, + "correlation": 16902, + "exaggerated": 16903, + "weekday": 16904, + "unification": 16905, + "bump": 16906, + "tracing": 16907, + "brig": 16908, + "afb": 16909, + "pathways": 16910, + "utilizing": 16911, + "##ners": 16912, + "mod": 16913, + "mb": 16914, + "disturbance": 16915, + "kneeling": 16916, + "##stad": 16917, + "##guchi": 16918, + "100th": 16919, + "pune": 16920, + "##thy": 16921, + "decreasing": 16922, + "168": 16923, + "manipulation": 16924, + "miriam": 16925, + "academia": 16926, + "ecosystem": 16927, + "occupational": 16928, + "rbi": 16929, + "##lem": 16930, + "rift": 16931, + "##14": 16932, + "rotary": 16933, + "stacked": 16934, + "incorporation": 16935, + "awakening": 16936, + "generators": 16937, + "guerrero": 16938, + "racist": 16939, + "##omy": 16940, + "cyber": 16941, + "derivatives": 16942, + "culminated": 16943, + "allie": 16944, + "annals": 16945, + "panzer": 16946, + "sainte": 16947, + "wikipedia": 16948, + "pops": 16949, + "zu": 16950, + "austro": 16951, + "##vate": 16952, + "algerian": 16953, + "politely": 16954, + "nicholson": 16955, + "mornings": 16956, + "educate": 16957, + "tastes": 16958, + "thrill": 16959, + "dartmouth": 16960, + "##gating": 16961, + "db": 16962, + "##jee": 16963, + "regan": 16964, + "differing": 16965, + "concentrating": 16966, + "choreography": 16967, + "divinity": 16968, + "##media": 16969, + "pledged": 16970, + "alexandre": 16971, + "routing": 16972, + "gregor": 16973, + "madeline": 16974, + "##idal": 16975, + "apocalypse": 16976, + "##hora": 16977, + "gunfire": 16978, + "culminating": 16979, + "elves": 16980, + "fined": 16981, + "liang": 16982, + "lam": 16983, + "programmed": 16984, + "tar": 16985, + "guessing": 16986, + "transparency": 16987, + "gabrielle": 16988, + "##gna": 16989, + "cancellation": 16990, + "flexibility": 16991, + "##lining": 16992, + "accession": 16993, + "shea": 16994, + "stronghold": 16995, + "nets": 16996, + "specializes": 16997, + "##rgan": 16998, + "abused": 16999, + "hasan": 17000, + "sgt": 17001, + "ling": 17002, + "exceeding": 17003, + "##₄": 17004, + "admiration": 17005, + "supermarket": 17006, + "##ark": 17007, + "photographers": 17008, + "specialised": 17009, + "tilt": 17010, + "resonance": 17011, + "hmm": 17012, + "perfume": 17013, + "380": 17014, + "sami": 17015, + "threatens": 17016, + "garland": 17017, + "botany": 17018, + "guarding": 17019, + "boiled": 17020, + "greet": 17021, + "puppy": 17022, + "russo": 17023, + "supplier": 17024, + "wilmington": 17025, + "vibrant": 17026, + "vijay": 17027, + "##bius": 17028, + "paralympic": 17029, + "grumbled": 17030, + "paige": 17031, + "faa": 17032, + "licking": 17033, + "margins": 17034, + "hurricanes": 17035, + "##gong": 17036, + "fest": 17037, + "grenade": 17038, + "ripping": 17039, + "##uz": 17040, + "counseling": 17041, + "weigh": 17042, + "##sian": 17043, + "needles": 17044, + "wiltshire": 17045, + "edison": 17046, + "costly": 17047, + "##not": 17048, + "fulton": 17049, + "tramway": 17050, + "redesigned": 17051, + "staffordshire": 17052, + "cache": 17053, + "gasping": 17054, + "watkins": 17055, + "sleepy": 17056, + "candidacy": 17057, + "##group": 17058, + "monkeys": 17059, + "timeline": 17060, + "throbbing": 17061, + "##bid": 17062, + "##sos": 17063, + "berth": 17064, + "uzbekistan": 17065, + "vanderbilt": 17066, + "bothering": 17067, + "overturned": 17068, + "ballots": 17069, + "gem": 17070, + "##iger": 17071, + "sunglasses": 17072, + "subscribers": 17073, + "hooker": 17074, + "compelling": 17075, + "ang": 17076, + "exceptionally": 17077, + "saloon": 17078, + "stab": 17079, + "##rdi": 17080, + "carla": 17081, + "terrifying": 17082, + "rom": 17083, + "##vision": 17084, + "coil": 17085, + "##oids": 17086, + "satisfying": 17087, + "vendors": 17088, + "31st": 17089, + "mackay": 17090, + "deities": 17091, + "overlooked": 17092, + "ambient": 17093, + "bahamas": 17094, + "felipe": 17095, + "olympia": 17096, + "whirled": 17097, + "botanist": 17098, + "advertised": 17099, + "tugging": 17100, + "##dden": 17101, + "disciples": 17102, + "morales": 17103, + "unionist": 17104, + "rites": 17105, + "foley": 17106, + "morse": 17107, + "motives": 17108, + "creepy": 17109, + "##₀": 17110, + "soo": 17111, + "##sz": 17112, + "bargain": 17113, + "highness": 17114, + "frightening": 17115, + "turnpike": 17116, + "tory": 17117, + "reorganization": 17118, + "##cer": 17119, + "depict": 17120, + "biographer": 17121, + "##walk": 17122, + "unopposed": 17123, + "manifesto": 17124, + "##gles": 17125, + "institut": 17126, + "emile": 17127, + "accidental": 17128, + "kapoor": 17129, + "##dam": 17130, + "kilkenny": 17131, + "cortex": 17132, + "lively": 17133, + "##13": 17134, + "romanesque": 17135, + "jain": 17136, + "shan": 17137, + "cannons": 17138, + "##ood": 17139, + "##ske": 17140, + "petrol": 17141, + "echoing": 17142, + "amalgamated": 17143, + "disappears": 17144, + "cautious": 17145, + "proposes": 17146, + "sanctions": 17147, + "trenton": 17148, + "##ر": 17149, + "flotilla": 17150, + "aus": 17151, + "contempt": 17152, + "tor": 17153, + "canary": 17154, + "cote": 17155, + "theirs": 17156, + "##hun": 17157, + "conceptual": 17158, + "deleted": 17159, + "fascinating": 17160, + "paso": 17161, + "blazing": 17162, + "elf": 17163, + "honourable": 17164, + "hutchinson": 17165, + "##eiro": 17166, + "##outh": 17167, + "##zin": 17168, + "surveyor": 17169, + "tee": 17170, + "amidst": 17171, + "wooded": 17172, + "reissue": 17173, + "intro": 17174, + "##ono": 17175, + "cobb": 17176, + "shelters": 17177, + "newsletter": 17178, + "hanson": 17179, + "brace": 17180, + "encoding": 17181, + "confiscated": 17182, + "dem": 17183, + "caravan": 17184, + "marino": 17185, + "scroll": 17186, + "melodic": 17187, + "cows": 17188, + "imam": 17189, + "##adi": 17190, + "##aneous": 17191, + "northward": 17192, + "searches": 17193, + "biodiversity": 17194, + "cora": 17195, + "310": 17196, + "roaring": 17197, + "##bers": 17198, + "connell": 17199, + "theologian": 17200, + "halo": 17201, + "compose": 17202, + "pathetic": 17203, + "unmarried": 17204, + "dynamo": 17205, + "##oot": 17206, + "az": 17207, + "calculation": 17208, + "toulouse": 17209, + "deserves": 17210, + "humour": 17211, + "nr": 17212, + "forgiveness": 17213, + "tam": 17214, + "undergone": 17215, + "martyr": 17216, + "pamela": 17217, + "myths": 17218, + "whore": 17219, + "counselor": 17220, + "hicks": 17221, + "290": 17222, + "heavens": 17223, + "battleship": 17224, + "electromagnetic": 17225, + "##bbs": 17226, + "stellar": 17227, + "establishments": 17228, + "presley": 17229, + "hopped": 17230, + "##chin": 17231, + "temptation": 17232, + "90s": 17233, + "wills": 17234, + "nas": 17235, + "##yuan": 17236, + "nhs": 17237, + "##nya": 17238, + "seminars": 17239, + "##yev": 17240, + "adaptations": 17241, + "gong": 17242, + "asher": 17243, + "lex": 17244, + "indicator": 17245, + "sikh": 17246, + "tobago": 17247, + "cites": 17248, + "goin": 17249, + "##yte": 17250, + "satirical": 17251, + "##gies": 17252, + "characterised": 17253, + "correspond": 17254, + "bubbles": 17255, + "lure": 17256, + "participates": 17257, + "##vid": 17258, + "eruption": 17259, + "skate": 17260, + "therapeutic": 17261, + "1785": 17262, + "canals": 17263, + "wholesale": 17264, + "defaulted": 17265, + "sac": 17266, + "460": 17267, + "petit": 17268, + "##zzled": 17269, + "virgil": 17270, + "leak": 17271, + "ravens": 17272, + "256": 17273, + "portraying": 17274, + "##yx": 17275, + "ghetto": 17276, + "creators": 17277, + "dams": 17278, + "portray": 17279, + "vicente": 17280, + "##rington": 17281, + "fae": 17282, + "namesake": 17283, + "bounty": 17284, + "##arium": 17285, + "joachim": 17286, + "##ota": 17287, + "##iser": 17288, + "aforementioned": 17289, + "axle": 17290, + "snout": 17291, + "depended": 17292, + "dismantled": 17293, + "reuben": 17294, + "480": 17295, + "##ibly": 17296, + "gallagher": 17297, + "##lau": 17298, + "##pd": 17299, + "earnest": 17300, + "##ieu": 17301, + "##iary": 17302, + "inflicted": 17303, + "objections": 17304, + "##llar": 17305, + "asa": 17306, + "gritted": 17307, + "##athy": 17308, + "jericho": 17309, + "##sea": 17310, + "##was": 17311, + "flick": 17312, + "underside": 17313, + "ceramics": 17314, + "undead": 17315, + "substituted": 17316, + "195": 17317, + "eastward": 17318, + "undoubtedly": 17319, + "wheeled": 17320, + "chimney": 17321, + "##iche": 17322, + "guinness": 17323, + "cb": 17324, + "##ager": 17325, + "siding": 17326, + "##bell": 17327, + "traitor": 17328, + "baptiste": 17329, + "disguised": 17330, + "inauguration": 17331, + "149": 17332, + "tipperary": 17333, + "choreographer": 17334, + "perched": 17335, + "warmed": 17336, + "stationary": 17337, + "eco": 17338, + "##ike": 17339, + "##ntes": 17340, + "bacterial": 17341, + "##aurus": 17342, + "flores": 17343, + "phosphate": 17344, + "##core": 17345, + "attacker": 17346, + "invaders": 17347, + "alvin": 17348, + "intersects": 17349, + "a1": 17350, + "indirectly": 17351, + "immigrated": 17352, + "businessmen": 17353, + "cornelius": 17354, + "valves": 17355, + "narrated": 17356, + "pill": 17357, + "sober": 17358, + "ul": 17359, + "nationale": 17360, + "monastic": 17361, + "applicants": 17362, + "scenery": 17363, + "##jack": 17364, + "161": 17365, + "motifs": 17366, + "constitutes": 17367, + "cpu": 17368, + "##osh": 17369, + "jurisdictions": 17370, + "sd": 17371, + "tuning": 17372, + "irritation": 17373, + "woven": 17374, + "##uddin": 17375, + "fertility": 17376, + "gao": 17377, + "##erie": 17378, + "antagonist": 17379, + "impatient": 17380, + "glacial": 17381, + "hides": 17382, + "boarded": 17383, + "denominations": 17384, + "interception": 17385, + "##jas": 17386, + "cookie": 17387, + "nicola": 17388, + "##tee": 17389, + "algebraic": 17390, + "marquess": 17391, + "bahn": 17392, + "parole": 17393, + "buyers": 17394, + "bait": 17395, + "turbines": 17396, + "paperwork": 17397, + "bestowed": 17398, + "natasha": 17399, + "renee": 17400, + "oceans": 17401, + "purchases": 17402, + "157": 17403, + "vaccine": 17404, + "215": 17405, + "##tock": 17406, + "fixtures": 17407, + "playhouse": 17408, + "integrate": 17409, + "jai": 17410, + "oswald": 17411, + "intellectuals": 17412, + "##cky": 17413, + "booked": 17414, + "nests": 17415, + "mortimer": 17416, + "##isi": 17417, + "obsession": 17418, + "sept": 17419, + "##gler": 17420, + "##sum": 17421, + "440": 17422, + "scrutiny": 17423, + "simultaneous": 17424, + "squinted": 17425, + "##shin": 17426, + "collects": 17427, + "oven": 17428, + "shankar": 17429, + "penned": 17430, + "remarkably": 17431, + "##я": 17432, + "slips": 17433, + "luggage": 17434, + "spectral": 17435, + "1786": 17436, + "collaborations": 17437, + "louie": 17438, + "consolidation": 17439, + "##ailed": 17440, + "##ivating": 17441, + "420": 17442, + "hoover": 17443, + "blackpool": 17444, + "harness": 17445, + "ignition": 17446, + "vest": 17447, + "tails": 17448, + "belmont": 17449, + "mongol": 17450, + "skinner": 17451, + "##nae": 17452, + "visually": 17453, + "mage": 17454, + "derry": 17455, + "##tism": 17456, + "##unce": 17457, + "stevie": 17458, + "transitional": 17459, + "##rdy": 17460, + "redskins": 17461, + "drying": 17462, + "prep": 17463, + "prospective": 17464, + "##21": 17465, + "annoyance": 17466, + "oversee": 17467, + "##loaded": 17468, + "fills": 17469, + "##books": 17470, + "##iki": 17471, + "announces": 17472, + "fda": 17473, + "scowled": 17474, + "respects": 17475, + "prasad": 17476, + "mystic": 17477, + "tucson": 17478, + "##vale": 17479, + "revue": 17480, + "springer": 17481, + "bankrupt": 17482, + "1772": 17483, + "aristotle": 17484, + "salvatore": 17485, + "habsburg": 17486, + "##geny": 17487, + "dal": 17488, + "natal": 17489, + "nut": 17490, + "pod": 17491, + "chewing": 17492, + "darts": 17493, + "moroccan": 17494, + "walkover": 17495, + "rosario": 17496, + "lenin": 17497, + "punjabi": 17498, + "##ße": 17499, + "grossed": 17500, + "scattering": 17501, + "wired": 17502, + "invasive": 17503, + "hui": 17504, + "polynomial": 17505, + "corridors": 17506, + "wakes": 17507, + "gina": 17508, + "portrays": 17509, + "##cratic": 17510, + "arid": 17511, + "retreating": 17512, + "erich": 17513, + "irwin": 17514, + "sniper": 17515, + "##dha": 17516, + "linen": 17517, + "lindsey": 17518, + "maneuver": 17519, + "butch": 17520, + "shutting": 17521, + "socio": 17522, + "bounce": 17523, + "commemorative": 17524, + "postseason": 17525, + "jeremiah": 17526, + "pines": 17527, + "275": 17528, + "mystical": 17529, + "beads": 17530, + "bp": 17531, + "abbas": 17532, + "furnace": 17533, + "bidding": 17534, + "consulted": 17535, + "assaulted": 17536, + "empirical": 17537, + "rubble": 17538, + "enclosure": 17539, + "sob": 17540, + "weakly": 17541, + "cancel": 17542, + "polly": 17543, + "yielded": 17544, + "##emann": 17545, + "curly": 17546, + "prediction": 17547, + "battered": 17548, + "70s": 17549, + "vhs": 17550, + "jacqueline": 17551, + "render": 17552, + "sails": 17553, + "barked": 17554, + "detailing": 17555, + "grayson": 17556, + "riga": 17557, + "sloane": 17558, + "raging": 17559, + "##yah": 17560, + "herbs": 17561, + "bravo": 17562, + "##athlon": 17563, + "alloy": 17564, + "giggle": 17565, + "imminent": 17566, + "suffers": 17567, + "assumptions": 17568, + "waltz": 17569, + "##itate": 17570, + "accomplishments": 17571, + "##ited": 17572, + "bathing": 17573, + "remixed": 17574, + "deception": 17575, + "prefix": 17576, + "##emia": 17577, + "deepest": 17578, + "##tier": 17579, + "##eis": 17580, + "balkan": 17581, + "frogs": 17582, + "##rong": 17583, + "slab": 17584, + "##pate": 17585, + "philosophers": 17586, + "peterborough": 17587, + "grains": 17588, + "imports": 17589, + "dickinson": 17590, + "rwanda": 17591, + "##atics": 17592, + "1774": 17593, + "dirk": 17594, + "lan": 17595, + "tablets": 17596, + "##rove": 17597, + "clone": 17598, + "##rice": 17599, + "caretaker": 17600, + "hostilities": 17601, + "mclean": 17602, + "##gre": 17603, + "regimental": 17604, + "treasures": 17605, + "norms": 17606, + "impose": 17607, + "tsar": 17608, + "tango": 17609, + "diplomacy": 17610, + "variously": 17611, + "complain": 17612, + "192": 17613, + "recognise": 17614, + "arrests": 17615, + "1779": 17616, + "celestial": 17617, + "pulitzer": 17618, + "##dus": 17619, + "bing": 17620, + "libretto": 17621, + "##moor": 17622, + "adele": 17623, + "splash": 17624, + "##rite": 17625, + "expectation": 17626, + "lds": 17627, + "confronts": 17628, + "##izer": 17629, + "spontaneous": 17630, + "harmful": 17631, + "wedge": 17632, + "entrepreneurs": 17633, + "buyer": 17634, + "##ope": 17635, + "bilingual": 17636, + "translate": 17637, + "rugged": 17638, + "conner": 17639, + "circulated": 17640, + "uae": 17641, + "eaton": 17642, + "##gra": 17643, + "##zzle": 17644, + "lingered": 17645, + "lockheed": 17646, + "vishnu": 17647, + "reelection": 17648, + "alonso": 17649, + "##oom": 17650, + "joints": 17651, + "yankee": 17652, + "headline": 17653, + "cooperate": 17654, + "heinz": 17655, + "laureate": 17656, + "invading": 17657, + "##sford": 17658, + "echoes": 17659, + "scandinavian": 17660, + "##dham": 17661, + "hugging": 17662, + "vitamin": 17663, + "salute": 17664, + "micah": 17665, + "hind": 17666, + "trader": 17667, + "##sper": 17668, + "radioactive": 17669, + "##ndra": 17670, + "militants": 17671, + "poisoned": 17672, + "ratified": 17673, + "remark": 17674, + "campeonato": 17675, + "deprived": 17676, + "wander": 17677, + "prop": 17678, + "##dong": 17679, + "outlook": 17680, + "##tani": 17681, + "##rix": 17682, + "##eye": 17683, + "chiang": 17684, + "darcy": 17685, + "##oping": 17686, + "mandolin": 17687, + "spice": 17688, + "statesman": 17689, + "babylon": 17690, + "182": 17691, + "walled": 17692, + "forgetting": 17693, + "afro": 17694, + "##cap": 17695, + "158": 17696, + "giorgio": 17697, + "buffer": 17698, + "##polis": 17699, + "planetary": 17700, + "##gis": 17701, + "overlap": 17702, + "terminals": 17703, + "kinda": 17704, + "centenary": 17705, + "##bir": 17706, + "arising": 17707, + "manipulate": 17708, + "elm": 17709, + "ke": 17710, + "1770": 17711, + "ak": 17712, + "##tad": 17713, + "chrysler": 17714, + "mapped": 17715, + "moose": 17716, + "pomeranian": 17717, + "quad": 17718, + "macarthur": 17719, + "assemblies": 17720, + "shoreline": 17721, + "recalls": 17722, + "stratford": 17723, + "##rted": 17724, + "noticeable": 17725, + "##evic": 17726, + "imp": 17727, + "##rita": 17728, + "##sque": 17729, + "accustomed": 17730, + "supplying": 17731, + "tents": 17732, + "disgusted": 17733, + "vogue": 17734, + "sipped": 17735, + "filters": 17736, + "khz": 17737, + "reno": 17738, + "selecting": 17739, + "luftwaffe": 17740, + "mcmahon": 17741, + "tyne": 17742, + "masterpiece": 17743, + "carriages": 17744, + "collided": 17745, + "dunes": 17746, + "exercised": 17747, + "flare": 17748, + "remembers": 17749, + "muzzle": 17750, + "##mobile": 17751, + "heck": 17752, + "##rson": 17753, + "burgess": 17754, + "lunged": 17755, + "middleton": 17756, + "boycott": 17757, + "bilateral": 17758, + "##sity": 17759, + "hazardous": 17760, + "lumpur": 17761, + "multiplayer": 17762, + "spotlight": 17763, + "jackets": 17764, + "goldman": 17765, + "liege": 17766, + "porcelain": 17767, + "rag": 17768, + "waterford": 17769, + "benz": 17770, + "attracts": 17771, + "hopeful": 17772, + "battling": 17773, + "ottomans": 17774, + "kensington": 17775, + "baked": 17776, + "hymns": 17777, + "cheyenne": 17778, + "lattice": 17779, + "levine": 17780, + "borrow": 17781, + "polymer": 17782, + "clashes": 17783, + "michaels": 17784, + "monitored": 17785, + "commitments": 17786, + "denounced": 17787, + "##25": 17788, + "##von": 17789, + "cavity": 17790, + "##oney": 17791, + "hobby": 17792, + "akin": 17793, + "##holders": 17794, + "futures": 17795, + "intricate": 17796, + "cornish": 17797, + "patty": 17798, + "##oned": 17799, + "illegally": 17800, + "dolphin": 17801, + "##lag": 17802, + "barlow": 17803, + "yellowish": 17804, + "maddie": 17805, + "apologized": 17806, + "luton": 17807, + "plagued": 17808, + "##puram": 17809, + "nana": 17810, + "##rds": 17811, + "sway": 17812, + "fanny": 17813, + "łodz": 17814, + "##rino": 17815, + "psi": 17816, + "suspicions": 17817, + "hanged": 17818, + "##eding": 17819, + "initiate": 17820, + "charlton": 17821, + "##por": 17822, + "nak": 17823, + "competent": 17824, + "235": 17825, + "analytical": 17826, + "annex": 17827, + "wardrobe": 17828, + "reservations": 17829, + "##rma": 17830, + "sect": 17831, + "162": 17832, + "fairfax": 17833, + "hedge": 17834, + "piled": 17835, + "buckingham": 17836, + "uneven": 17837, + "bauer": 17838, + "simplicity": 17839, + "snyder": 17840, + "interpret": 17841, + "accountability": 17842, + "donors": 17843, + "moderately": 17844, + "byrd": 17845, + "continents": 17846, + "##cite": 17847, + "##max": 17848, + "disciple": 17849, + "hr": 17850, + "jamaican": 17851, + "ping": 17852, + "nominees": 17853, + "##uss": 17854, + "mongolian": 17855, + "diver": 17856, + "attackers": 17857, + "eagerly": 17858, + "ideological": 17859, + "pillows": 17860, + "miracles": 17861, + "apartheid": 17862, + "revolver": 17863, + "sulfur": 17864, + "clinics": 17865, + "moran": 17866, + "163": 17867, + "##enko": 17868, + "ile": 17869, + "katy": 17870, + "rhetoric": 17871, + "##icated": 17872, + "chronology": 17873, + "recycling": 17874, + "##hrer": 17875, + "elongated": 17876, + "mughal": 17877, + "pascal": 17878, + "profiles": 17879, + "vibration": 17880, + "databases": 17881, + "domination": 17882, + "##fare": 17883, + "##rant": 17884, + "matthias": 17885, + "digest": 17886, + "rehearsal": 17887, + "polling": 17888, + "weiss": 17889, + "initiation": 17890, + "reeves": 17891, + "clinging": 17892, + "flourished": 17893, + "impress": 17894, + "ngo": 17895, + "##hoff": 17896, + "##ume": 17897, + "buckley": 17898, + "symposium": 17899, + "rhythms": 17900, + "weed": 17901, + "emphasize": 17902, + "transforming": 17903, + "##taking": 17904, + "##gence": 17905, + "##yman": 17906, + "accountant": 17907, + "analyze": 17908, + "flicker": 17909, + "foil": 17910, + "priesthood": 17911, + "voluntarily": 17912, + "decreases": 17913, + "##80": 17914, + "##hya": 17915, + "slater": 17916, + "sv": 17917, + "charting": 17918, + "mcgill": 17919, + "##lde": 17920, + "moreno": 17921, + "##iu": 17922, + "besieged": 17923, + "zur": 17924, + "robes": 17925, + "##phic": 17926, + "admitting": 17927, + "api": 17928, + "deported": 17929, + "turmoil": 17930, + "peyton": 17931, + "earthquakes": 17932, + "##ares": 17933, + "nationalists": 17934, + "beau": 17935, + "clair": 17936, + "brethren": 17937, + "interrupt": 17938, + "welch": 17939, + "curated": 17940, + "galerie": 17941, + "requesting": 17942, + "164": 17943, + "##ested": 17944, + "impending": 17945, + "steward": 17946, + "viper": 17947, + "##vina": 17948, + "complaining": 17949, + "beautifully": 17950, + "brandy": 17951, + "foam": 17952, + "nl": 17953, + "1660": 17954, + "##cake": 17955, + "alessandro": 17956, + "punches": 17957, + "laced": 17958, + "explanations": 17959, + "##lim": 17960, + "attribute": 17961, + "clit": 17962, + "reggie": 17963, + "discomfort": 17964, + "##cards": 17965, + "smoothed": 17966, + "whales": 17967, + "##cene": 17968, + "adler": 17969, + "countered": 17970, + "duffy": 17971, + "disciplinary": 17972, + "widening": 17973, + "recipe": 17974, + "reliance": 17975, + "conducts": 17976, + "goats": 17977, + "gradient": 17978, + "preaching": 17979, + "##shaw": 17980, + "matilda": 17981, + "quasi": 17982, + "striped": 17983, + "meridian": 17984, + "cannabis": 17985, + "cordoba": 17986, + "certificates": 17987, + "##agh": 17988, + "##tering": 17989, + "graffiti": 17990, + "hangs": 17991, + "pilgrims": 17992, + "repeats": 17993, + "##ych": 17994, + "revive": 17995, + "urine": 17996, + "etat": 17997, + "##hawk": 17998, + "fueled": 17999, + "belts": 18000, + "fuzzy": 18001, + "susceptible": 18002, + "##hang": 18003, + "mauritius": 18004, + "salle": 18005, + "sincere": 18006, + "beers": 18007, + "hooks": 18008, + "##cki": 18009, + "arbitration": 18010, + "entrusted": 18011, + "advise": 18012, + "sniffed": 18013, + "seminar": 18014, + "junk": 18015, + "donnell": 18016, + "processors": 18017, + "principality": 18018, + "strapped": 18019, + "celia": 18020, + "mendoza": 18021, + "everton": 18022, + "fortunes": 18023, + "prejudice": 18024, + "starving": 18025, + "reassigned": 18026, + "steamer": 18027, + "##lund": 18028, + "tuck": 18029, + "evenly": 18030, + "foreman": 18031, + "##ffen": 18032, + "dans": 18033, + "375": 18034, + "envisioned": 18035, + "slit": 18036, + "##xy": 18037, + "baseman": 18038, + "liberia": 18039, + "rosemary": 18040, + "##weed": 18041, + "electrified": 18042, + "periodically": 18043, + "potassium": 18044, + "stride": 18045, + "contexts": 18046, + "sperm": 18047, + "slade": 18048, + "mariners": 18049, + "influx": 18050, + "bianca": 18051, + "subcommittee": 18052, + "##rane": 18053, + "spilling": 18054, + "icao": 18055, + "estuary": 18056, + "##nock": 18057, + "delivers": 18058, + "iphone": 18059, + "##ulata": 18060, + "isa": 18061, + "mira": 18062, + "bohemian": 18063, + "dessert": 18064, + "##sbury": 18065, + "welcoming": 18066, + "proudly": 18067, + "slowing": 18068, + "##chs": 18069, + "musee": 18070, + "ascension": 18071, + "russ": 18072, + "##vian": 18073, + "waits": 18074, + "##psy": 18075, + "africans": 18076, + "exploit": 18077, + "##morphic": 18078, + "gov": 18079, + "eccentric": 18080, + "crab": 18081, + "peck": 18082, + "##ull": 18083, + "entrances": 18084, + "formidable": 18085, + "marketplace": 18086, + "groom": 18087, + "bolted": 18088, + "metabolism": 18089, + "patton": 18090, + "robbins": 18091, + "courier": 18092, + "payload": 18093, + "endure": 18094, + "##ifier": 18095, + "andes": 18096, + "refrigerator": 18097, + "##pr": 18098, + "ornate": 18099, + "##uca": 18100, + "ruthless": 18101, + "illegitimate": 18102, + "masonry": 18103, + "strasbourg": 18104, + "bikes": 18105, + "adobe": 18106, + "##³": 18107, + "apples": 18108, + "quintet": 18109, + "willingly": 18110, + "niche": 18111, + "bakery": 18112, + "corpses": 18113, + "energetic": 18114, + "##cliffe": 18115, + "##sser": 18116, + "##ards": 18117, + "177": 18118, + "centimeters": 18119, + "centro": 18120, + "fuscous": 18121, + "cretaceous": 18122, + "rancho": 18123, + "##yde": 18124, + "andrei": 18125, + "telecom": 18126, + "tottenham": 18127, + "oasis": 18128, + "ordination": 18129, + "vulnerability": 18130, + "presiding": 18131, + "corey": 18132, + "cp": 18133, + "penguins": 18134, + "sims": 18135, + "##pis": 18136, + "malawi": 18137, + "piss": 18138, + "##48": 18139, + "correction": 18140, + "##cked": 18141, + "##ffle": 18142, + "##ryn": 18143, + "countdown": 18144, + "detectives": 18145, + "psychiatrist": 18146, + "psychedelic": 18147, + "dinosaurs": 18148, + "blouse": 18149, + "##get": 18150, + "choi": 18151, + "vowed": 18152, + "##oz": 18153, + "randomly": 18154, + "##pol": 18155, + "49ers": 18156, + "scrub": 18157, + "blanche": 18158, + "bruins": 18159, + "dusseldorf": 18160, + "##using": 18161, + "unwanted": 18162, + "##ums": 18163, + "212": 18164, + "dominique": 18165, + "elevations": 18166, + "headlights": 18167, + "om": 18168, + "laguna": 18169, + "##oga": 18170, + "1750": 18171, + "famously": 18172, + "ignorance": 18173, + "shrewsbury": 18174, + "##aine": 18175, + "ajax": 18176, + "breuning": 18177, + "che": 18178, + "confederacy": 18179, + "greco": 18180, + "overhaul": 18181, + "##screen": 18182, + "paz": 18183, + "skirts": 18184, + "disagreement": 18185, + "cruelty": 18186, + "jagged": 18187, + "phoebe": 18188, + "shifter": 18189, + "hovered": 18190, + "viruses": 18191, + "##wes": 18192, + "mandy": 18193, + "##lined": 18194, + "##gc": 18195, + "landlord": 18196, + "squirrel": 18197, + "dashed": 18198, + "##ι": 18199, + "ornamental": 18200, + "gag": 18201, + "wally": 18202, + "grange": 18203, + "literal": 18204, + "spurs": 18205, + "undisclosed": 18206, + "proceeding": 18207, + "yin": 18208, + "##text": 18209, + "billie": 18210, + "orphan": 18211, + "spanned": 18212, + "humidity": 18213, + "indy": 18214, + "weighted": 18215, + "presentations": 18216, + "explosions": 18217, + "lucian": 18218, + "##tary": 18219, + "vaughn": 18220, + "hindus": 18221, + "##anga": 18222, + "##hell": 18223, + "psycho": 18224, + "171": 18225, + "daytona": 18226, + "protects": 18227, + "efficiently": 18228, + "rematch": 18229, + "sly": 18230, + "tandem": 18231, + "##oya": 18232, + "rebranded": 18233, + "impaired": 18234, + "hee": 18235, + "metropolis": 18236, + "peach": 18237, + "godfrey": 18238, + "diaspora": 18239, + "ethnicity": 18240, + "prosperous": 18241, + "gleaming": 18242, + "dar": 18243, + "grossing": 18244, + "playback": 18245, + "##rden": 18246, + "stripe": 18247, + "pistols": 18248, + "##tain": 18249, + "births": 18250, + "labelled": 18251, + "##cating": 18252, + "172": 18253, + "rudy": 18254, + "alba": 18255, + "##onne": 18256, + "aquarium": 18257, + "hostility": 18258, + "##gb": 18259, + "##tase": 18260, + "shudder": 18261, + "sumatra": 18262, + "hardest": 18263, + "lakers": 18264, + "consonant": 18265, + "creeping": 18266, + "demos": 18267, + "homicide": 18268, + "capsule": 18269, + "zeke": 18270, + "liberties": 18271, + "expulsion": 18272, + "pueblo": 18273, + "##comb": 18274, + "trait": 18275, + "transporting": 18276, + "##ddin": 18277, + "##neck": 18278, + "##yna": 18279, + "depart": 18280, + "gregg": 18281, + "mold": 18282, + "ledge": 18283, + "hangar": 18284, + "oldham": 18285, + "playboy": 18286, + "termination": 18287, + "analysts": 18288, + "gmbh": 18289, + "romero": 18290, + "##itic": 18291, + "insist": 18292, + "cradle": 18293, + "filthy": 18294, + "brightness": 18295, + "slash": 18296, + "shootout": 18297, + "deposed": 18298, + "bordering": 18299, + "##truct": 18300, + "isis": 18301, + "microwave": 18302, + "tumbled": 18303, + "sheltered": 18304, + "cathy": 18305, + "werewolves": 18306, + "messy": 18307, + "andersen": 18308, + "convex": 18309, + "clapped": 18310, + "clinched": 18311, + "satire": 18312, + "wasting": 18313, + "edo": 18314, + "vc": 18315, + "rufus": 18316, + "##jak": 18317, + "mont": 18318, + "##etti": 18319, + "poznan": 18320, + "##keeping": 18321, + "restructuring": 18322, + "transverse": 18323, + "##rland": 18324, + "azerbaijani": 18325, + "slovene": 18326, + "gestures": 18327, + "roommate": 18328, + "choking": 18329, + "shear": 18330, + "##quist": 18331, + "vanguard": 18332, + "oblivious": 18333, + "##hiro": 18334, + "disagreed": 18335, + "baptism": 18336, + "##lich": 18337, + "coliseum": 18338, + "##aceae": 18339, + "salvage": 18340, + "societe": 18341, + "cory": 18342, + "locke": 18343, + "relocation": 18344, + "relying": 18345, + "versailles": 18346, + "ahl": 18347, + "swelling": 18348, + "##elo": 18349, + "cheerful": 18350, + "##word": 18351, + "##edes": 18352, + "gin": 18353, + "sarajevo": 18354, + "obstacle": 18355, + "diverted": 18356, + "##nac": 18357, + "messed": 18358, + "thoroughbred": 18359, + "fluttered": 18360, + "utrecht": 18361, + "chewed": 18362, + "acquaintance": 18363, + "assassins": 18364, + "dispatch": 18365, + "mirza": 18366, + "##wart": 18367, + "nike": 18368, + "salzburg": 18369, + "swell": 18370, + "yen": 18371, + "##gee": 18372, + "idle": 18373, + "ligue": 18374, + "samson": 18375, + "##nds": 18376, + "##igh": 18377, + "playful": 18378, + "spawned": 18379, + "##cise": 18380, + "tease": 18381, + "##case": 18382, + "burgundy": 18383, + "##bot": 18384, + "stirring": 18385, + "skeptical": 18386, + "interceptions": 18387, + "marathi": 18388, + "##dies": 18389, + "bedrooms": 18390, + "aroused": 18391, + "pinch": 18392, + "##lik": 18393, + "preferences": 18394, + "tattoos": 18395, + "buster": 18396, + "digitally": 18397, + "projecting": 18398, + "rust": 18399, + "##ital": 18400, + "kitten": 18401, + "priorities": 18402, + "addison": 18403, + "pseudo": 18404, + "##guard": 18405, + "dusk": 18406, + "icons": 18407, + "sermon": 18408, + "##psis": 18409, + "##iba": 18410, + "bt": 18411, + "##lift": 18412, + "##xt": 18413, + "ju": 18414, + "truce": 18415, + "rink": 18416, + "##dah": 18417, + "##wy": 18418, + "defects": 18419, + "psychiatry": 18420, + "offences": 18421, + "calculate": 18422, + "glucose": 18423, + "##iful": 18424, + "##rized": 18425, + "##unda": 18426, + "francaise": 18427, + "##hari": 18428, + "richest": 18429, + "warwickshire": 18430, + "carly": 18431, + "1763": 18432, + "purity": 18433, + "redemption": 18434, + "lending": 18435, + "##cious": 18436, + "muse": 18437, + "bruises": 18438, + "cerebral": 18439, + "aero": 18440, + "carving": 18441, + "##name": 18442, + "preface": 18443, + "terminology": 18444, + "invade": 18445, + "monty": 18446, + "##int": 18447, + "anarchist": 18448, + "blurred": 18449, + "##iled": 18450, + "rossi": 18451, + "treats": 18452, + "guts": 18453, + "shu": 18454, + "foothills": 18455, + "ballads": 18456, + "undertaking": 18457, + "premise": 18458, + "cecilia": 18459, + "affiliates": 18460, + "blasted": 18461, + "conditional": 18462, + "wilder": 18463, + "minors": 18464, + "drone": 18465, + "rudolph": 18466, + "buffy": 18467, + "swallowing": 18468, + "horton": 18469, + "attested": 18470, + "##hop": 18471, + "rutherford": 18472, + "howell": 18473, + "primetime": 18474, + "livery": 18475, + "penal": 18476, + "##bis": 18477, + "minimize": 18478, + "hydro": 18479, + "wrecked": 18480, + "wrought": 18481, + "palazzo": 18482, + "##gling": 18483, + "cans": 18484, + "vernacular": 18485, + "friedman": 18486, + "nobleman": 18487, + "shale": 18488, + "walnut": 18489, + "danielle": 18490, + "##ection": 18491, + "##tley": 18492, + "sears": 18493, + "##kumar": 18494, + "chords": 18495, + "lend": 18496, + "flipping": 18497, + "streamed": 18498, + "por": 18499, + "dracula": 18500, + "gallons": 18501, + "sacrifices": 18502, + "gamble": 18503, + "orphanage": 18504, + "##iman": 18505, + "mckenzie": 18506, + "##gible": 18507, + "boxers": 18508, + "daly": 18509, + "##balls": 18510, + "##ان": 18511, + "208": 18512, + "##ific": 18513, + "##rative": 18514, + "##iq": 18515, + "exploited": 18516, + "slated": 18517, + "##uity": 18518, + "circling": 18519, + "hillary": 18520, + "pinched": 18521, + "goldberg": 18522, + "provost": 18523, + "campaigning": 18524, + "lim": 18525, + "piles": 18526, + "ironically": 18527, + "jong": 18528, + "mohan": 18529, + "successors": 18530, + "usaf": 18531, + "##tem": 18532, + "##ught": 18533, + "autobiographical": 18534, + "haute": 18535, + "preserves": 18536, + "##ending": 18537, + "acquitted": 18538, + "comparisons": 18539, + "203": 18540, + "hydroelectric": 18541, + "gangs": 18542, + "cypriot": 18543, + "torpedoes": 18544, + "rushes": 18545, + "chrome": 18546, + "derive": 18547, + "bumps": 18548, + "instability": 18549, + "fiat": 18550, + "pets": 18551, + "##mbe": 18552, + "silas": 18553, + "dye": 18554, + "reckless": 18555, + "settler": 18556, + "##itation": 18557, + "info": 18558, + "heats": 18559, + "##writing": 18560, + "176": 18561, + "canonical": 18562, + "maltese": 18563, + "fins": 18564, + "mushroom": 18565, + "stacy": 18566, + "aspen": 18567, + "avid": 18568, + "##kur": 18569, + "##loading": 18570, + "vickers": 18571, + "gaston": 18572, + "hillside": 18573, + "statutes": 18574, + "wilde": 18575, + "gail": 18576, + "kung": 18577, + "sabine": 18578, + "comfortably": 18579, + "motorcycles": 18580, + "##rgo": 18581, + "169": 18582, + "pneumonia": 18583, + "fetch": 18584, + "##sonic": 18585, + "axel": 18586, + "faintly": 18587, + "parallels": 18588, + "##oop": 18589, + "mclaren": 18590, + "spouse": 18591, + "compton": 18592, + "interdisciplinary": 18593, + "miner": 18594, + "##eni": 18595, + "181": 18596, + "clamped": 18597, + "##chal": 18598, + "##llah": 18599, + "separates": 18600, + "versa": 18601, + "##mler": 18602, + "scarborough": 18603, + "labrador": 18604, + "##lity": 18605, + "##osing": 18606, + "rutgers": 18607, + "hurdles": 18608, + "como": 18609, + "166": 18610, + "burt": 18611, + "divers": 18612, + "##100": 18613, + "wichita": 18614, + "cade": 18615, + "coincided": 18616, + "##erson": 18617, + "bruised": 18618, + "mla": 18619, + "##pper": 18620, + "vineyard": 18621, + "##ili": 18622, + "##brush": 18623, + "notch": 18624, + "mentioning": 18625, + "jase": 18626, + "hearted": 18627, + "kits": 18628, + "doe": 18629, + "##acle": 18630, + "pomerania": 18631, + "##ady": 18632, + "ronan": 18633, + "seizure": 18634, + "pavel": 18635, + "problematic": 18636, + "##zaki": 18637, + "domenico": 18638, + "##ulin": 18639, + "catering": 18640, + "penelope": 18641, + "dependence": 18642, + "parental": 18643, + "emilio": 18644, + "ministerial": 18645, + "atkinson": 18646, + "##bolic": 18647, + "clarkson": 18648, + "chargers": 18649, + "colby": 18650, + "grill": 18651, + "peeked": 18652, + "arises": 18653, + "summon": 18654, + "##aged": 18655, + "fools": 18656, + "##grapher": 18657, + "faculties": 18658, + "qaeda": 18659, + "##vial": 18660, + "garner": 18661, + "refurbished": 18662, + "##hwa": 18663, + "geelong": 18664, + "disasters": 18665, + "nudged": 18666, + "bs": 18667, + "shareholder": 18668, + "lori": 18669, + "algae": 18670, + "reinstated": 18671, + "rot": 18672, + "##ades": 18673, + "##nous": 18674, + "invites": 18675, + "stainless": 18676, + "183": 18677, + "inclusive": 18678, + "##itude": 18679, + "diocesan": 18680, + "til": 18681, + "##icz": 18682, + "denomination": 18683, + "##xa": 18684, + "benton": 18685, + "floral": 18686, + "registers": 18687, + "##ider": 18688, + "##erman": 18689, + "##kell": 18690, + "absurd": 18691, + "brunei": 18692, + "guangzhou": 18693, + "hitter": 18694, + "retaliation": 18695, + "##uled": 18696, + "##eve": 18697, + "blanc": 18698, + "nh": 18699, + "consistency": 18700, + "contamination": 18701, + "##eres": 18702, + "##rner": 18703, + "dire": 18704, + "palermo": 18705, + "broadcasters": 18706, + "diaries": 18707, + "inspire": 18708, + "vols": 18709, + "brewer": 18710, + "tightening": 18711, + "ky": 18712, + "mixtape": 18713, + "hormone": 18714, + "##tok": 18715, + "stokes": 18716, + "##color": 18717, + "##dly": 18718, + "##ssi": 18719, + "pg": 18720, + "##ometer": 18721, + "##lington": 18722, + "sanitation": 18723, + "##tility": 18724, + "intercontinental": 18725, + "apps": 18726, + "##adt": 18727, + "¹⁄₂": 18728, + "cylinders": 18729, + "economies": 18730, + "favourable": 18731, + "unison": 18732, + "croix": 18733, + "gertrude": 18734, + "odyssey": 18735, + "vanity": 18736, + "dangling": 18737, + "##logists": 18738, + "upgrades": 18739, + "dice": 18740, + "middleweight": 18741, + "practitioner": 18742, + "##ight": 18743, + "206": 18744, + "henrik": 18745, + "parlor": 18746, + "orion": 18747, + "angered": 18748, + "lac": 18749, + "python": 18750, + "blurted": 18751, + "##rri": 18752, + "sensual": 18753, + "intends": 18754, + "swings": 18755, + "angled": 18756, + "##phs": 18757, + "husky": 18758, + "attain": 18759, + "peerage": 18760, + "precinct": 18761, + "textiles": 18762, + "cheltenham": 18763, + "shuffled": 18764, + "dai": 18765, + "confess": 18766, + "tasting": 18767, + "bhutan": 18768, + "##riation": 18769, + "tyrone": 18770, + "segregation": 18771, + "abrupt": 18772, + "ruiz": 18773, + "##rish": 18774, + "smirked": 18775, + "blackwell": 18776, + "confidential": 18777, + "browning": 18778, + "amounted": 18779, + "##put": 18780, + "vase": 18781, + "scarce": 18782, + "fabulous": 18783, + "raided": 18784, + "staple": 18785, + "guyana": 18786, + "unemployed": 18787, + "glider": 18788, + "shay": 18789, + "##tow": 18790, + "carmine": 18791, + "troll": 18792, + "intervene": 18793, + "squash": 18794, + "superstar": 18795, + "##uce": 18796, + "cylindrical": 18797, + "len": 18798, + "roadway": 18799, + "researched": 18800, + "handy": 18801, + "##rium": 18802, + "##jana": 18803, + "meta": 18804, + "lao": 18805, + "declares": 18806, + "##rring": 18807, + "##tadt": 18808, + "##elin": 18809, + "##kova": 18810, + "willem": 18811, + "shrubs": 18812, + "napoleonic": 18813, + "realms": 18814, + "skater": 18815, + "qi": 18816, + "volkswagen": 18817, + "##ł": 18818, + "tad": 18819, + "hara": 18820, + "archaeologist": 18821, + "awkwardly": 18822, + "eerie": 18823, + "##kind": 18824, + "wiley": 18825, + "##heimer": 18826, + "##24": 18827, + "titus": 18828, + "organizers": 18829, + "cfl": 18830, + "crusaders": 18831, + "lama": 18832, + "usb": 18833, + "vent": 18834, + "enraged": 18835, + "thankful": 18836, + "occupants": 18837, + "maximilian": 18838, + "##gaard": 18839, + "possessing": 18840, + "textbooks": 18841, + "##oran": 18842, + "collaborator": 18843, + "quaker": 18844, + "##ulo": 18845, + "avalanche": 18846, + "mono": 18847, + "silky": 18848, + "straits": 18849, + "isaiah": 18850, + "mustang": 18851, + "surged": 18852, + "resolutions": 18853, + "potomac": 18854, + "descend": 18855, + "cl": 18856, + "kilograms": 18857, + "plato": 18858, + "strains": 18859, + "saturdays": 18860, + "##olin": 18861, + "bernstein": 18862, + "##ype": 18863, + "holstein": 18864, + "ponytail": 18865, + "##watch": 18866, + "belize": 18867, + "conversely": 18868, + "heroine": 18869, + "perpetual": 18870, + "##ylus": 18871, + "charcoal": 18872, + "piedmont": 18873, + "glee": 18874, + "negotiating": 18875, + "backdrop": 18876, + "prologue": 18877, + "##jah": 18878, + "##mmy": 18879, + "pasadena": 18880, + "climbs": 18881, + "ramos": 18882, + "sunni": 18883, + "##holm": 18884, + "##tner": 18885, + "##tri": 18886, + "anand": 18887, + "deficiency": 18888, + "hertfordshire": 18889, + "stout": 18890, + "##avi": 18891, + "aperture": 18892, + "orioles": 18893, + "##irs": 18894, + "doncaster": 18895, + "intrigued": 18896, + "bombed": 18897, + "coating": 18898, + "otis": 18899, + "##mat": 18900, + "cocktail": 18901, + "##jit": 18902, + "##eto": 18903, + "amir": 18904, + "arousal": 18905, + "sar": 18906, + "##proof": 18907, + "##act": 18908, + "##ories": 18909, + "dixie": 18910, + "pots": 18911, + "##bow": 18912, + "whereabouts": 18913, + "159": 18914, + "##fted": 18915, + "drains": 18916, + "bullying": 18917, + "cottages": 18918, + "scripture": 18919, + "coherent": 18920, + "fore": 18921, + "poe": 18922, + "appetite": 18923, + "##uration": 18924, + "sampled": 18925, + "##ators": 18926, + "##dp": 18927, + "derrick": 18928, + "rotor": 18929, + "jays": 18930, + "peacock": 18931, + "installment": 18932, + "##rro": 18933, + "advisors": 18934, + "##coming": 18935, + "rodeo": 18936, + "scotch": 18937, + "##mot": 18938, + "##db": 18939, + "##fen": 18940, + "##vant": 18941, + "ensued": 18942, + "rodrigo": 18943, + "dictatorship": 18944, + "martyrs": 18945, + "twenties": 18946, + "##н": 18947, + "towed": 18948, + "incidence": 18949, + "marta": 18950, + "rainforest": 18951, + "sai": 18952, + "scaled": 18953, + "##cles": 18954, + "oceanic": 18955, + "qualifiers": 18956, + "symphonic": 18957, + "mcbride": 18958, + "dislike": 18959, + "generalized": 18960, + "aubrey": 18961, + "colonization": 18962, + "##iation": 18963, + "##lion": 18964, + "##ssing": 18965, + "disliked": 18966, + "lublin": 18967, + "salesman": 18968, + "##ulates": 18969, + "spherical": 18970, + "whatsoever": 18971, + "sweating": 18972, + "avalon": 18973, + "contention": 18974, + "punt": 18975, + "severity": 18976, + "alderman": 18977, + "atari": 18978, + "##dina": 18979, + "##grant": 18980, + "##rop": 18981, + "scarf": 18982, + "seville": 18983, + "vertices": 18984, + "annexation": 18985, + "fairfield": 18986, + "fascination": 18987, + "inspiring": 18988, + "launches": 18989, + "palatinate": 18990, + "regretted": 18991, + "##rca": 18992, + "feral": 18993, + "##iom": 18994, + "elk": 18995, + "nap": 18996, + "olsen": 18997, + "reddy": 18998, + "yong": 18999, + "##leader": 19000, + "##iae": 19001, + "garment": 19002, + "transports": 19003, + "feng": 19004, + "gracie": 19005, + "outrage": 19006, + "viceroy": 19007, + "insides": 19008, + "##esis": 19009, + "breakup": 19010, + "grady": 19011, + "organizer": 19012, + "softer": 19013, + "grimaced": 19014, + "222": 19015, + "murals": 19016, + "galicia": 19017, + "arranging": 19018, + "vectors": 19019, + "##rsten": 19020, + "bas": 19021, + "##sb": 19022, + "##cens": 19023, + "sloan": 19024, + "##eka": 19025, + "bitten": 19026, + "ara": 19027, + "fender": 19028, + "nausea": 19029, + "bumped": 19030, + "kris": 19031, + "banquet": 19032, + "comrades": 19033, + "detector": 19034, + "persisted": 19035, + "##llan": 19036, + "adjustment": 19037, + "endowed": 19038, + "cinemas": 19039, + "##shot": 19040, + "sellers": 19041, + "##uman": 19042, + "peek": 19043, + "epa": 19044, + "kindly": 19045, + "neglect": 19046, + "simpsons": 19047, + "talon": 19048, + "mausoleum": 19049, + "runaway": 19050, + "hangul": 19051, + "lookout": 19052, + "##cic": 19053, + "rewards": 19054, + "coughed": 19055, + "acquainted": 19056, + "chloride": 19057, + "##ald": 19058, + "quicker": 19059, + "accordion": 19060, + "neolithic": 19061, + "##qa": 19062, + "artemis": 19063, + "coefficient": 19064, + "lenny": 19065, + "pandora": 19066, + "tx": 19067, + "##xed": 19068, + "ecstasy": 19069, + "litter": 19070, + "segunda": 19071, + "chairperson": 19072, + "gemma": 19073, + "hiss": 19074, + "rumor": 19075, + "vow": 19076, + "nasal": 19077, + "antioch": 19078, + "compensate": 19079, + "patiently": 19080, + "transformers": 19081, + "##eded": 19082, + "judo": 19083, + "morrow": 19084, + "penis": 19085, + "posthumous": 19086, + "philips": 19087, + "bandits": 19088, + "husbands": 19089, + "denote": 19090, + "flaming": 19091, + "##any": 19092, + "##phones": 19093, + "langley": 19094, + "yorker": 19095, + "1760": 19096, + "walters": 19097, + "##uo": 19098, + "##kle": 19099, + "gubernatorial": 19100, + "fatty": 19101, + "samsung": 19102, + "leroy": 19103, + "outlaw": 19104, + "##nine": 19105, + "unpublished": 19106, + "poole": 19107, + "jakob": 19108, + "##ᵢ": 19109, + "##ₙ": 19110, + "crete": 19111, + "distorted": 19112, + "superiority": 19113, + "##dhi": 19114, + "intercept": 19115, + "crust": 19116, + "mig": 19117, + "claus": 19118, + "crashes": 19119, + "positioning": 19120, + "188": 19121, + "stallion": 19122, + "301": 19123, + "frontal": 19124, + "armistice": 19125, + "##estinal": 19126, + "elton": 19127, + "aj": 19128, + "encompassing": 19129, + "camel": 19130, + "commemorated": 19131, + "malaria": 19132, + "woodward": 19133, + "calf": 19134, + "cigar": 19135, + "penetrate": 19136, + "##oso": 19137, + "willard": 19138, + "##rno": 19139, + "##uche": 19140, + "illustrate": 19141, + "amusing": 19142, + "convergence": 19143, + "noteworthy": 19144, + "##lma": 19145, + "##rva": 19146, + "journeys": 19147, + "realise": 19148, + "manfred": 19149, + "##sable": 19150, + "410": 19151, + "##vocation": 19152, + "hearings": 19153, + "fiance": 19154, + "##posed": 19155, + "educators": 19156, + "provoked": 19157, + "adjusting": 19158, + "##cturing": 19159, + "modular": 19160, + "stockton": 19161, + "paterson": 19162, + "vlad": 19163, + "rejects": 19164, + "electors": 19165, + "selena": 19166, + "maureen": 19167, + "##tres": 19168, + "uber": 19169, + "##rce": 19170, + "swirled": 19171, + "##num": 19172, + "proportions": 19173, + "nanny": 19174, + "pawn": 19175, + "naturalist": 19176, + "parma": 19177, + "apostles": 19178, + "awoke": 19179, + "ethel": 19180, + "wen": 19181, + "##bey": 19182, + "monsoon": 19183, + "overview": 19184, + "##inating": 19185, + "mccain": 19186, + "rendition": 19187, + "risky": 19188, + "adorned": 19189, + "##ih": 19190, + "equestrian": 19191, + "germain": 19192, + "nj": 19193, + "conspicuous": 19194, + "confirming": 19195, + "##yoshi": 19196, + "shivering": 19197, + "##imeter": 19198, + "milestone": 19199, + "rumours": 19200, + "flinched": 19201, + "bounds": 19202, + "smacked": 19203, + "token": 19204, + "##bei": 19205, + "lectured": 19206, + "automobiles": 19207, + "##shore": 19208, + "impacted": 19209, + "##iable": 19210, + "nouns": 19211, + "nero": 19212, + "##leaf": 19213, + "ismail": 19214, + "prostitute": 19215, + "trams": 19216, + "##lace": 19217, + "bridget": 19218, + "sud": 19219, + "stimulus": 19220, + "impressions": 19221, + "reins": 19222, + "revolves": 19223, + "##oud": 19224, + "##gned": 19225, + "giro": 19226, + "honeymoon": 19227, + "##swell": 19228, + "criterion": 19229, + "##sms": 19230, + "##uil": 19231, + "libyan": 19232, + "prefers": 19233, + "##osition": 19234, + "211": 19235, + "preview": 19236, + "sucks": 19237, + "accusation": 19238, + "bursts": 19239, + "metaphor": 19240, + "diffusion": 19241, + "tolerate": 19242, + "faye": 19243, + "betting": 19244, + "cinematographer": 19245, + "liturgical": 19246, + "specials": 19247, + "bitterly": 19248, + "humboldt": 19249, + "##ckle": 19250, + "flux": 19251, + "rattled": 19252, + "##itzer": 19253, + "archaeologists": 19254, + "odor": 19255, + "authorised": 19256, + "marshes": 19257, + "discretion": 19258, + "##ов": 19259, + "alarmed": 19260, + "archaic": 19261, + "inverse": 19262, + "##leton": 19263, + "explorers": 19264, + "##pine": 19265, + "drummond": 19266, + "tsunami": 19267, + "woodlands": 19268, + "##minate": 19269, + "##tland": 19270, + "booklet": 19271, + "insanity": 19272, + "owning": 19273, + "insert": 19274, + "crafted": 19275, + "calculus": 19276, + "##tore": 19277, + "receivers": 19278, + "##bt": 19279, + "stung": 19280, + "##eca": 19281, + "##nched": 19282, + "prevailing": 19283, + "travellers": 19284, + "eyeing": 19285, + "lila": 19286, + "graphs": 19287, + "##borne": 19288, + "178": 19289, + "julien": 19290, + "##won": 19291, + "morale": 19292, + "adaptive": 19293, + "therapist": 19294, + "erica": 19295, + "cw": 19296, + "libertarian": 19297, + "bowman": 19298, + "pitches": 19299, + "vita": 19300, + "##ional": 19301, + "crook": 19302, + "##ads": 19303, + "##entation": 19304, + "caledonia": 19305, + "mutiny": 19306, + "##sible": 19307, + "1840s": 19308, + "automation": 19309, + "##ß": 19310, + "flock": 19311, + "##pia": 19312, + "ironic": 19313, + "pathology": 19314, + "##imus": 19315, + "remarried": 19316, + "##22": 19317, + "joker": 19318, + "withstand": 19319, + "energies": 19320, + "##att": 19321, + "shropshire": 19322, + "hostages": 19323, + "madeleine": 19324, + "tentatively": 19325, + "conflicting": 19326, + "mateo": 19327, + "recipes": 19328, + "euros": 19329, + "ol": 19330, + "mercenaries": 19331, + "nico": 19332, + "##ndon": 19333, + "albuquerque": 19334, + "augmented": 19335, + "mythical": 19336, + "bel": 19337, + "freud": 19338, + "##child": 19339, + "cough": 19340, + "##lica": 19341, + "365": 19342, + "freddy": 19343, + "lillian": 19344, + "genetically": 19345, + "nuremberg": 19346, + "calder": 19347, + "209": 19348, + "bonn": 19349, + "outdoors": 19350, + "paste": 19351, + "suns": 19352, + "urgency": 19353, + "vin": 19354, + "restraint": 19355, + "tyson": 19356, + "##cera": 19357, + "##selle": 19358, + "barrage": 19359, + "bethlehem": 19360, + "kahn": 19361, + "##par": 19362, + "mounts": 19363, + "nippon": 19364, + "barony": 19365, + "happier": 19366, + "ryu": 19367, + "makeshift": 19368, + "sheldon": 19369, + "blushed": 19370, + "castillo": 19371, + "barking": 19372, + "listener": 19373, + "taped": 19374, + "bethel": 19375, + "fluent": 19376, + "headlines": 19377, + "pornography": 19378, + "rum": 19379, + "disclosure": 19380, + "sighing": 19381, + "mace": 19382, + "doubling": 19383, + "gunther": 19384, + "manly": 19385, + "##plex": 19386, + "rt": 19387, + "interventions": 19388, + "physiological": 19389, + "forwards": 19390, + "emerges": 19391, + "##tooth": 19392, + "##gny": 19393, + "compliment": 19394, + "rib": 19395, + "recession": 19396, + "visibly": 19397, + "barge": 19398, + "faults": 19399, + "connector": 19400, + "exquisite": 19401, + "prefect": 19402, + "##rlin": 19403, + "patio": 19404, + "##cured": 19405, + "elevators": 19406, + "brandt": 19407, + "italics": 19408, + "pena": 19409, + "173": 19410, + "wasp": 19411, + "satin": 19412, + "ea": 19413, + "botswana": 19414, + "graceful": 19415, + "respectable": 19416, + "##jima": 19417, + "##rter": 19418, + "##oic": 19419, + "franciscan": 19420, + "generates": 19421, + "##dl": 19422, + "alfredo": 19423, + "disgusting": 19424, + "##olate": 19425, + "##iously": 19426, + "sherwood": 19427, + "warns": 19428, + "cod": 19429, + "promo": 19430, + "cheryl": 19431, + "sino": 19432, + "##ة": 19433, + "##escu": 19434, + "twitch": 19435, + "##zhi": 19436, + "brownish": 19437, + "thom": 19438, + "ortiz": 19439, + "##dron": 19440, + "densely": 19441, + "##beat": 19442, + "carmel": 19443, + "reinforce": 19444, + "##bana": 19445, + "187": 19446, + "anastasia": 19447, + "downhill": 19448, + "vertex": 19449, + "contaminated": 19450, + "remembrance": 19451, + "harmonic": 19452, + "homework": 19453, + "##sol": 19454, + "fiancee": 19455, + "gears": 19456, + "olds": 19457, + "angelica": 19458, + "loft": 19459, + "ramsay": 19460, + "quiz": 19461, + "colliery": 19462, + "sevens": 19463, + "##cape": 19464, + "autism": 19465, + "##hil": 19466, + "walkway": 19467, + "##boats": 19468, + "ruben": 19469, + "abnormal": 19470, + "ounce": 19471, + "khmer": 19472, + "##bbe": 19473, + "zachary": 19474, + "bedside": 19475, + "morphology": 19476, + "punching": 19477, + "##olar": 19478, + "sparrow": 19479, + "convinces": 19480, + "##35": 19481, + "hewitt": 19482, + "queer": 19483, + "remastered": 19484, + "rods": 19485, + "mabel": 19486, + "solemn": 19487, + "notified": 19488, + "lyricist": 19489, + "symmetric": 19490, + "##xide": 19491, + "174": 19492, + "encore": 19493, + "passports": 19494, + "wildcats": 19495, + "##uni": 19496, + "baja": 19497, + "##pac": 19498, + "mildly": 19499, + "##ease": 19500, + "bleed": 19501, + "commodity": 19502, + "mounds": 19503, + "glossy": 19504, + "orchestras": 19505, + "##omo": 19506, + "damian": 19507, + "prelude": 19508, + "ambitions": 19509, + "##vet": 19510, + "awhile": 19511, + "remotely": 19512, + "##aud": 19513, + "asserts": 19514, + "imply": 19515, + "##iques": 19516, + "distinctly": 19517, + "modelling": 19518, + "remedy": 19519, + "##dded": 19520, + "windshield": 19521, + "dani": 19522, + "xiao": 19523, + "##endra": 19524, + "audible": 19525, + "powerplant": 19526, + "1300": 19527, + "invalid": 19528, + "elemental": 19529, + "acquisitions": 19530, + "##hala": 19531, + "immaculate": 19532, + "libby": 19533, + "plata": 19534, + "smuggling": 19535, + "ventilation": 19536, + "denoted": 19537, + "minh": 19538, + "##morphism": 19539, + "430": 19540, + "differed": 19541, + "dion": 19542, + "kelley": 19543, + "lore": 19544, + "mocking": 19545, + "sabbath": 19546, + "spikes": 19547, + "hygiene": 19548, + "drown": 19549, + "runoff": 19550, + "stylized": 19551, + "tally": 19552, + "liberated": 19553, + "aux": 19554, + "interpreter": 19555, + "righteous": 19556, + "aba": 19557, + "siren": 19558, + "reaper": 19559, + "pearce": 19560, + "millie": 19561, + "##cier": 19562, + "##yra": 19563, + "gaius": 19564, + "##iso": 19565, + "captures": 19566, + "##ttering": 19567, + "dorm": 19568, + "claudio": 19569, + "##sic": 19570, + "benches": 19571, + "knighted": 19572, + "blackness": 19573, + "##ored": 19574, + "discount": 19575, + "fumble": 19576, + "oxidation": 19577, + "routed": 19578, + "##ς": 19579, + "novak": 19580, + "perpendicular": 19581, + "spoiled": 19582, + "fracture": 19583, + "splits": 19584, + "##urt": 19585, + "pads": 19586, + "topology": 19587, + "##cats": 19588, + "axes": 19589, + "fortunate": 19590, + "offenders": 19591, + "protestants": 19592, + "esteem": 19593, + "221": 19594, + "broadband": 19595, + "convened": 19596, + "frankly": 19597, + "hound": 19598, + "prototypes": 19599, + "isil": 19600, + "facilitated": 19601, + "keel": 19602, + "##sher": 19603, + "sahara": 19604, + "awaited": 19605, + "bubba": 19606, + "orb": 19607, + "prosecutors": 19608, + "186": 19609, + "hem": 19610, + "520": 19611, + "##xing": 19612, + "relaxing": 19613, + "remnant": 19614, + "romney": 19615, + "sorted": 19616, + "slalom": 19617, + "stefano": 19618, + "ulrich": 19619, + "##active": 19620, + "exemption": 19621, + "folder": 19622, + "pauses": 19623, + "foliage": 19624, + "hitchcock": 19625, + "epithet": 19626, + "204": 19627, + "criticisms": 19628, + "##aca": 19629, + "ballistic": 19630, + "brody": 19631, + "hinduism": 19632, + "chaotic": 19633, + "youths": 19634, + "equals": 19635, + "##pala": 19636, + "pts": 19637, + "thicker": 19638, + "analogous": 19639, + "capitalist": 19640, + "improvised": 19641, + "overseeing": 19642, + "sinatra": 19643, + "ascended": 19644, + "beverage": 19645, + "##tl": 19646, + "straightforward": 19647, + "##kon": 19648, + "curran": 19649, + "##west": 19650, + "bois": 19651, + "325": 19652, + "induce": 19653, + "surveying": 19654, + "emperors": 19655, + "sax": 19656, + "unpopular": 19657, + "##kk": 19658, + "cartoonist": 19659, + "fused": 19660, + "##mble": 19661, + "unto": 19662, + "##yuki": 19663, + "localities": 19664, + "##cko": 19665, + "##ln": 19666, + "darlington": 19667, + "slain": 19668, + "academie": 19669, + "lobbying": 19670, + "sediment": 19671, + "puzzles": 19672, + "##grass": 19673, + "defiance": 19674, + "dickens": 19675, + "manifest": 19676, + "tongues": 19677, + "alumnus": 19678, + "arbor": 19679, + "coincide": 19680, + "184": 19681, + "appalachian": 19682, + "mustafa": 19683, + "examiner": 19684, + "cabaret": 19685, + "traumatic": 19686, + "yves": 19687, + "bracelet": 19688, + "draining": 19689, + "heroin": 19690, + "magnum": 19691, + "baths": 19692, + "odessa": 19693, + "consonants": 19694, + "mitsubishi": 19695, + "##gua": 19696, + "kellan": 19697, + "vaudeville": 19698, + "##fr": 19699, + "joked": 19700, + "null": 19701, + "straps": 19702, + "probation": 19703, + "##ław": 19704, + "ceded": 19705, + "interfaces": 19706, + "##pas": 19707, + "##zawa": 19708, + "blinding": 19709, + "viet": 19710, + "224": 19711, + "rothschild": 19712, + "museo": 19713, + "640": 19714, + "huddersfield": 19715, + "##vr": 19716, + "tactic": 19717, + "##storm": 19718, + "brackets": 19719, + "dazed": 19720, + "incorrectly": 19721, + "##vu": 19722, + "reg": 19723, + "glazed": 19724, + "fearful": 19725, + "manifold": 19726, + "benefited": 19727, + "irony": 19728, + "##sun": 19729, + "stumbling": 19730, + "##rte": 19731, + "willingness": 19732, + "balkans": 19733, + "mei": 19734, + "wraps": 19735, + "##aba": 19736, + "injected": 19737, + "##lea": 19738, + "gu": 19739, + "syed": 19740, + "harmless": 19741, + "##hammer": 19742, + "bray": 19743, + "takeoff": 19744, + "poppy": 19745, + "timor": 19746, + "cardboard": 19747, + "astronaut": 19748, + "purdue": 19749, + "weeping": 19750, + "southbound": 19751, + "cursing": 19752, + "stalls": 19753, + "diagonal": 19754, + "##neer": 19755, + "lamar": 19756, + "bryce": 19757, + "comte": 19758, + "weekdays": 19759, + "harrington": 19760, + "##uba": 19761, + "negatively": 19762, + "##see": 19763, + "lays": 19764, + "grouping": 19765, + "##cken": 19766, + "##henko": 19767, + "affirmed": 19768, + "halle": 19769, + "modernist": 19770, + "##lai": 19771, + "hodges": 19772, + "smelling": 19773, + "aristocratic": 19774, + "baptized": 19775, + "dismiss": 19776, + "justification": 19777, + "oilers": 19778, + "##now": 19779, + "coupling": 19780, + "qin": 19781, + "snack": 19782, + "healer": 19783, + "##qing": 19784, + "gardener": 19785, + "layla": 19786, + "battled": 19787, + "formulated": 19788, + "stephenson": 19789, + "gravitational": 19790, + "##gill": 19791, + "##jun": 19792, + "1768": 19793, + "granny": 19794, + "coordinating": 19795, + "suites": 19796, + "##cd": 19797, + "##ioned": 19798, + "monarchs": 19799, + "##cote": 19800, + "##hips": 19801, + "sep": 19802, + "blended": 19803, + "apr": 19804, + "barrister": 19805, + "deposition": 19806, + "fia": 19807, + "mina": 19808, + "policemen": 19809, + "paranoid": 19810, + "##pressed": 19811, + "churchyard": 19812, + "covert": 19813, + "crumpled": 19814, + "creep": 19815, + "abandoning": 19816, + "tr": 19817, + "transmit": 19818, + "conceal": 19819, + "barr": 19820, + "understands": 19821, + "readiness": 19822, + "spire": 19823, + "##cology": 19824, + "##enia": 19825, + "##erry": 19826, + "610": 19827, + "startling": 19828, + "unlock": 19829, + "vida": 19830, + "bowled": 19831, + "slots": 19832, + "##nat": 19833, + "##islav": 19834, + "spaced": 19835, + "trusting": 19836, + "admire": 19837, + "rig": 19838, + "##ink": 19839, + "slack": 19840, + "##70": 19841, + "mv": 19842, + "207": 19843, + "casualty": 19844, + "##wei": 19845, + "classmates": 19846, + "##odes": 19847, + "##rar": 19848, + "##rked": 19849, + "amherst": 19850, + "furnished": 19851, + "evolve": 19852, + "foundry": 19853, + "menace": 19854, + "mead": 19855, + "##lein": 19856, + "flu": 19857, + "wesleyan": 19858, + "##kled": 19859, + "monterey": 19860, + "webber": 19861, + "##vos": 19862, + "wil": 19863, + "##mith": 19864, + "##на": 19865, + "bartholomew": 19866, + "justices": 19867, + "restrained": 19868, + "##cke": 19869, + "amenities": 19870, + "191": 19871, + "mediated": 19872, + "sewage": 19873, + "trenches": 19874, + "ml": 19875, + "mainz": 19876, + "##thus": 19877, + "1800s": 19878, + "##cula": 19879, + "##inski": 19880, + "caine": 19881, + "bonding": 19882, + "213": 19883, + "converts": 19884, + "spheres": 19885, + "superseded": 19886, + "marianne": 19887, + "crypt": 19888, + "sweaty": 19889, + "ensign": 19890, + "historia": 19891, + "##br": 19892, + "spruce": 19893, + "##post": 19894, + "##ask": 19895, + "forks": 19896, + "thoughtfully": 19897, + "yukon": 19898, + "pamphlet": 19899, + "ames": 19900, + "##uter": 19901, + "karma": 19902, + "##yya": 19903, + "bryn": 19904, + "negotiation": 19905, + "sighs": 19906, + "incapable": 19907, + "##mbre": 19908, + "##ntial": 19909, + "actresses": 19910, + "taft": 19911, + "##mill": 19912, + "luce": 19913, + "prevailed": 19914, + "##amine": 19915, + "1773": 19916, + "motionless": 19917, + "envoy": 19918, + "testify": 19919, + "investing": 19920, + "sculpted": 19921, + "instructors": 19922, + "provence": 19923, + "kali": 19924, + "cullen": 19925, + "horseback": 19926, + "##while": 19927, + "goodwin": 19928, + "##jos": 19929, + "gaa": 19930, + "norte": 19931, + "##ldon": 19932, + "modify": 19933, + "wavelength": 19934, + "abd": 19935, + "214": 19936, + "skinned": 19937, + "sprinter": 19938, + "forecast": 19939, + "scheduling": 19940, + "marries": 19941, + "squared": 19942, + "tentative": 19943, + "##chman": 19944, + "boer": 19945, + "##isch": 19946, + "bolts": 19947, + "swap": 19948, + "fisherman": 19949, + "assyrian": 19950, + "impatiently": 19951, + "guthrie": 19952, + "martins": 19953, + "murdoch": 19954, + "194": 19955, + "tanya": 19956, + "nicely": 19957, + "dolly": 19958, + "lacy": 19959, + "med": 19960, + "##45": 19961, + "syn": 19962, + "decks": 19963, + "fashionable": 19964, + "millionaire": 19965, + "##ust": 19966, + "surfing": 19967, + "##ml": 19968, + "##ision": 19969, + "heaved": 19970, + "tammy": 19971, + "consulate": 19972, + "attendees": 19973, + "routinely": 19974, + "197": 19975, + "fuse": 19976, + "saxophonist": 19977, + "backseat": 19978, + "malaya": 19979, + "##lord": 19980, + "scowl": 19981, + "tau": 19982, + "##ishly": 19983, + "193": 19984, + "sighted": 19985, + "steaming": 19986, + "##rks": 19987, + "303": 19988, + "911": 19989, + "##holes": 19990, + "##hong": 19991, + "ching": 19992, + "##wife": 19993, + "bless": 19994, + "conserved": 19995, + "jurassic": 19996, + "stacey": 19997, + "unix": 19998, + "zion": 19999, + "chunk": 20000, + "rigorous": 20001, + "blaine": 20002, + "198": 20003, + "peabody": 20004, + "slayer": 20005, + "dismay": 20006, + "brewers": 20007, + "nz": 20008, + "##jer": 20009, + "det": 20010, + "##glia": 20011, + "glover": 20012, + "postwar": 20013, + "int": 20014, + "penetration": 20015, + "sylvester": 20016, + "imitation": 20017, + "vertically": 20018, + "airlift": 20019, + "heiress": 20020, + "knoxville": 20021, + "viva": 20022, + "##uin": 20023, + "390": 20024, + "macon": 20025, + "##rim": 20026, + "##fighter": 20027, + "##gonal": 20028, + "janice": 20029, + "##orescence": 20030, + "##wari": 20031, + "marius": 20032, + "belongings": 20033, + "leicestershire": 20034, + "196": 20035, + "blanco": 20036, + "inverted": 20037, + "preseason": 20038, + "sanity": 20039, + "sobbing": 20040, + "##due": 20041, + "##elt": 20042, + "##dled": 20043, + "collingwood": 20044, + "regeneration": 20045, + "flickering": 20046, + "shortest": 20047, + "##mount": 20048, + "##osi": 20049, + "feminism": 20050, + "##lat": 20051, + "sherlock": 20052, + "cabinets": 20053, + "fumbled": 20054, + "northbound": 20055, + "precedent": 20056, + "snaps": 20057, + "##mme": 20058, + "researching": 20059, + "##akes": 20060, + "guillaume": 20061, + "insights": 20062, + "manipulated": 20063, + "vapor": 20064, + "neighbour": 20065, + "sap": 20066, + "gangster": 20067, + "frey": 20068, + "f1": 20069, + "stalking": 20070, + "scarcely": 20071, + "callie": 20072, + "barnett": 20073, + "tendencies": 20074, + "audi": 20075, + "doomed": 20076, + "assessing": 20077, + "slung": 20078, + "panchayat": 20079, + "ambiguous": 20080, + "bartlett": 20081, + "##etto": 20082, + "distributing": 20083, + "violating": 20084, + "wolverhampton": 20085, + "##hetic": 20086, + "swami": 20087, + "histoire": 20088, + "##urus": 20089, + "liable": 20090, + "pounder": 20091, + "groin": 20092, + "hussain": 20093, + "larsen": 20094, + "popping": 20095, + "surprises": 20096, + "##atter": 20097, + "vie": 20098, + "curt": 20099, + "##station": 20100, + "mute": 20101, + "relocate": 20102, + "musicals": 20103, + "authorization": 20104, + "richter": 20105, + "##sef": 20106, + "immortality": 20107, + "tna": 20108, + "bombings": 20109, + "##press": 20110, + "deteriorated": 20111, + "yiddish": 20112, + "##acious": 20113, + "robbed": 20114, + "colchester": 20115, + "cs": 20116, + "pmid": 20117, + "ao": 20118, + "verified": 20119, + "balancing": 20120, + "apostle": 20121, + "swayed": 20122, + "recognizable": 20123, + "oxfordshire": 20124, + "retention": 20125, + "nottinghamshire": 20126, + "contender": 20127, + "judd": 20128, + "invitational": 20129, + "shrimp": 20130, + "uhf": 20131, + "##icient": 20132, + "cleaner": 20133, + "longitudinal": 20134, + "tanker": 20135, + "##mur": 20136, + "acronym": 20137, + "broker": 20138, + "koppen": 20139, + "sundance": 20140, + "suppliers": 20141, + "##gil": 20142, + "4000": 20143, + "clipped": 20144, + "fuels": 20145, + "petite": 20146, + "##anne": 20147, + "landslide": 20148, + "helene": 20149, + "diversion": 20150, + "populous": 20151, + "landowners": 20152, + "auspices": 20153, + "melville": 20154, + "quantitative": 20155, + "##xes": 20156, + "ferries": 20157, + "nicky": 20158, + "##llus": 20159, + "doo": 20160, + "haunting": 20161, + "roche": 20162, + "carver": 20163, + "downed": 20164, + "unavailable": 20165, + "##pathy": 20166, + "approximation": 20167, + "hiroshima": 20168, + "##hue": 20169, + "garfield": 20170, + "valle": 20171, + "comparatively": 20172, + "keyboardist": 20173, + "traveler": 20174, + "##eit": 20175, + "congestion": 20176, + "calculating": 20177, + "subsidiaries": 20178, + "##bate": 20179, + "serb": 20180, + "modernization": 20181, + "fairies": 20182, + "deepened": 20183, + "ville": 20184, + "averages": 20185, + "##lore": 20186, + "inflammatory": 20187, + "tonga": 20188, + "##itch": 20189, + "co₂": 20190, + "squads": 20191, + "##hea": 20192, + "gigantic": 20193, + "serum": 20194, + "enjoyment": 20195, + "retailer": 20196, + "verona": 20197, + "35th": 20198, + "cis": 20199, + "##phobic": 20200, + "magna": 20201, + "technicians": 20202, + "##vati": 20203, + "arithmetic": 20204, + "##sport": 20205, + "levin": 20206, + "##dation": 20207, + "amtrak": 20208, + "chow": 20209, + "sienna": 20210, + "##eyer": 20211, + "backstage": 20212, + "entrepreneurship": 20213, + "##otic": 20214, + "learnt": 20215, + "tao": 20216, + "##udy": 20217, + "worcestershire": 20218, + "formulation": 20219, + "baggage": 20220, + "hesitant": 20221, + "bali": 20222, + "sabotage": 20223, + "##kari": 20224, + "barren": 20225, + "enhancing": 20226, + "murmur": 20227, + "pl": 20228, + "freshly": 20229, + "putnam": 20230, + "syntax": 20231, + "aces": 20232, + "medicines": 20233, + "resentment": 20234, + "bandwidth": 20235, + "##sier": 20236, + "grins": 20237, + "chili": 20238, + "guido": 20239, + "##sei": 20240, + "framing": 20241, + "implying": 20242, + "gareth": 20243, + "lissa": 20244, + "genevieve": 20245, + "pertaining": 20246, + "admissions": 20247, + "geo": 20248, + "thorpe": 20249, + "proliferation": 20250, + "sato": 20251, + "bela": 20252, + "analyzing": 20253, + "parting": 20254, + "##gor": 20255, + "awakened": 20256, + "##isman": 20257, + "huddled": 20258, + "secrecy": 20259, + "##kling": 20260, + "hush": 20261, + "gentry": 20262, + "540": 20263, + "dungeons": 20264, + "##ego": 20265, + "coasts": 20266, + "##utz": 20267, + "sacrificed": 20268, + "##chule": 20269, + "landowner": 20270, + "mutually": 20271, + "prevalence": 20272, + "programmer": 20273, + "adolescent": 20274, + "disrupted": 20275, + "seaside": 20276, + "gee": 20277, + "trusts": 20278, + "vamp": 20279, + "georgie": 20280, + "##nesian": 20281, + "##iol": 20282, + "schedules": 20283, + "sindh": 20284, + "##market": 20285, + "etched": 20286, + "hm": 20287, + "sparse": 20288, + "bey": 20289, + "beaux": 20290, + "scratching": 20291, + "gliding": 20292, + "unidentified": 20293, + "216": 20294, + "collaborating": 20295, + "gems": 20296, + "jesuits": 20297, + "oro": 20298, + "accumulation": 20299, + "shaping": 20300, + "mbe": 20301, + "anal": 20302, + "##xin": 20303, + "231": 20304, + "enthusiasts": 20305, + "newscast": 20306, + "##egan": 20307, + "janata": 20308, + "dewey": 20309, + "parkinson": 20310, + "179": 20311, + "ankara": 20312, + "biennial": 20313, + "towering": 20314, + "dd": 20315, + "inconsistent": 20316, + "950": 20317, + "##chet": 20318, + "thriving": 20319, + "terminate": 20320, + "cabins": 20321, + "furiously": 20322, + "eats": 20323, + "advocating": 20324, + "donkey": 20325, + "marley": 20326, + "muster": 20327, + "phyllis": 20328, + "leiden": 20329, + "##user": 20330, + "grassland": 20331, + "glittering": 20332, + "iucn": 20333, + "loneliness": 20334, + "217": 20335, + "memorandum": 20336, + "armenians": 20337, + "##ddle": 20338, + "popularized": 20339, + "rhodesia": 20340, + "60s": 20341, + "lame": 20342, + "##illon": 20343, + "sans": 20344, + "bikini": 20345, + "header": 20346, + "orbits": 20347, + "##xx": 20348, + "##finger": 20349, + "##ulator": 20350, + "sharif": 20351, + "spines": 20352, + "biotechnology": 20353, + "strolled": 20354, + "naughty": 20355, + "yates": 20356, + "##wire": 20357, + "fremantle": 20358, + "milo": 20359, + "##mour": 20360, + "abducted": 20361, + "removes": 20362, + "##atin": 20363, + "humming": 20364, + "wonderland": 20365, + "##chrome": 20366, + "##ester": 20367, + "hume": 20368, + "pivotal": 20369, + "##rates": 20370, + "armand": 20371, + "grams": 20372, + "believers": 20373, + "elector": 20374, + "rte": 20375, + "apron": 20376, + "bis": 20377, + "scraped": 20378, + "##yria": 20379, + "endorsement": 20380, + "initials": 20381, + "##llation": 20382, + "eps": 20383, + "dotted": 20384, + "hints": 20385, + "buzzing": 20386, + "emigration": 20387, + "nearer": 20388, + "##tom": 20389, + "indicators": 20390, + "##ulu": 20391, + "coarse": 20392, + "neutron": 20393, + "protectorate": 20394, + "##uze": 20395, + "directional": 20396, + "exploits": 20397, + "pains": 20398, + "loire": 20399, + "1830s": 20400, + "proponents": 20401, + "guggenheim": 20402, + "rabbits": 20403, + "ritchie": 20404, + "305": 20405, + "hectare": 20406, + "inputs": 20407, + "hutton": 20408, + "##raz": 20409, + "verify": 20410, + "##ako": 20411, + "boilers": 20412, + "longitude": 20413, + "##lev": 20414, + "skeletal": 20415, + "yer": 20416, + "emilia": 20417, + "citrus": 20418, + "compromised": 20419, + "##gau": 20420, + "pokemon": 20421, + "prescription": 20422, + "paragraph": 20423, + "eduard": 20424, + "cadillac": 20425, + "attire": 20426, + "categorized": 20427, + "kenyan": 20428, + "weddings": 20429, + "charley": 20430, + "##bourg": 20431, + "entertain": 20432, + "monmouth": 20433, + "##lles": 20434, + "nutrients": 20435, + "davey": 20436, + "mesh": 20437, + "incentive": 20438, + "practised": 20439, + "ecosystems": 20440, + "kemp": 20441, + "subdued": 20442, + "overheard": 20443, + "##rya": 20444, + "bodily": 20445, + "maxim": 20446, + "##nius": 20447, + "apprenticeship": 20448, + "ursula": 20449, + "##fight": 20450, + "lodged": 20451, + "rug": 20452, + "silesian": 20453, + "unconstitutional": 20454, + "patel": 20455, + "inspected": 20456, + "coyote": 20457, + "unbeaten": 20458, + "##hak": 20459, + "34th": 20460, + "disruption": 20461, + "convict": 20462, + "parcel": 20463, + "##cl": 20464, + "##nham": 20465, + "collier": 20466, + "implicated": 20467, + "mallory": 20468, + "##iac": 20469, + "##lab": 20470, + "susannah": 20471, + "winkler": 20472, + "##rber": 20473, + "shia": 20474, + "phelps": 20475, + "sediments": 20476, + "graphical": 20477, + "robotic": 20478, + "##sner": 20479, + "adulthood": 20480, + "mart": 20481, + "smoked": 20482, + "##isto": 20483, + "kathryn": 20484, + "clarified": 20485, + "##aran": 20486, + "divides": 20487, + "convictions": 20488, + "oppression": 20489, + "pausing": 20490, + "burying": 20491, + "##mt": 20492, + "federico": 20493, + "mathias": 20494, + "eileen": 20495, + "##tana": 20496, + "kite": 20497, + "hunched": 20498, + "##acies": 20499, + "189": 20500, + "##atz": 20501, + "disadvantage": 20502, + "liza": 20503, + "kinetic": 20504, + "greedy": 20505, + "paradox": 20506, + "yokohama": 20507, + "dowager": 20508, + "trunks": 20509, + "ventured": 20510, + "##gement": 20511, + "gupta": 20512, + "vilnius": 20513, + "olaf": 20514, + "##thest": 20515, + "crimean": 20516, + "hopper": 20517, + "##ej": 20518, + "progressively": 20519, + "arturo": 20520, + "mouthed": 20521, + "arrondissement": 20522, + "##fusion": 20523, + "rubin": 20524, + "simulcast": 20525, + "oceania": 20526, + "##orum": 20527, + "##stra": 20528, + "##rred": 20529, + "busiest": 20530, + "intensely": 20531, + "navigator": 20532, + "cary": 20533, + "##vine": 20534, + "##hini": 20535, + "##bies": 20536, + "fife": 20537, + "rowe": 20538, + "rowland": 20539, + "posing": 20540, + "insurgents": 20541, + "shafts": 20542, + "lawsuits": 20543, + "activate": 20544, + "conor": 20545, + "inward": 20546, + "culturally": 20547, + "garlic": 20548, + "265": 20549, + "##eering": 20550, + "eclectic": 20551, + "##hui": 20552, + "##kee": 20553, + "##nl": 20554, + "furrowed": 20555, + "vargas": 20556, + "meteorological": 20557, + "rendezvous": 20558, + "##aus": 20559, + "culinary": 20560, + "commencement": 20561, + "##dition": 20562, + "quota": 20563, + "##notes": 20564, + "mommy": 20565, + "salaries": 20566, + "overlapping": 20567, + "mule": 20568, + "##iology": 20569, + "##mology": 20570, + "sums": 20571, + "wentworth": 20572, + "##isk": 20573, + "##zione": 20574, + "mainline": 20575, + "subgroup": 20576, + "##illy": 20577, + "hack": 20578, + "plaintiff": 20579, + "verdi": 20580, + "bulb": 20581, + "differentiation": 20582, + "engagements": 20583, + "multinational": 20584, + "supplemented": 20585, + "bertrand": 20586, + "caller": 20587, + "regis": 20588, + "##naire": 20589, + "##sler": 20590, + "##arts": 20591, + "##imated": 20592, + "blossom": 20593, + "propagation": 20594, + "kilometer": 20595, + "viaduct": 20596, + "vineyards": 20597, + "##uate": 20598, + "beckett": 20599, + "optimization": 20600, + "golfer": 20601, + "songwriters": 20602, + "seminal": 20603, + "semitic": 20604, + "thud": 20605, + "volatile": 20606, + "evolving": 20607, + "ridley": 20608, + "##wley": 20609, + "trivial": 20610, + "distributions": 20611, + "scandinavia": 20612, + "jiang": 20613, + "##ject": 20614, + "wrestled": 20615, + "insistence": 20616, + "##dio": 20617, + "emphasizes": 20618, + "napkin": 20619, + "##ods": 20620, + "adjunct": 20621, + "rhyme": 20622, + "##ricted": 20623, + "##eti": 20624, + "hopeless": 20625, + "surrounds": 20626, + "tremble": 20627, + "32nd": 20628, + "smoky": 20629, + "##ntly": 20630, + "oils": 20631, + "medicinal": 20632, + "padded": 20633, + "steer": 20634, + "wilkes": 20635, + "219": 20636, + "255": 20637, + "concessions": 20638, + "hue": 20639, + "uniquely": 20640, + "blinded": 20641, + "landon": 20642, + "yahoo": 20643, + "##lane": 20644, + "hendrix": 20645, + "commemorating": 20646, + "dex": 20647, + "specify": 20648, + "chicks": 20649, + "##ggio": 20650, + "intercity": 20651, + "1400": 20652, + "morley": 20653, + "##torm": 20654, + "highlighting": 20655, + "##oting": 20656, + "pang": 20657, + "oblique": 20658, + "stalled": 20659, + "##liner": 20660, + "flirting": 20661, + "newborn": 20662, + "1769": 20663, + "bishopric": 20664, + "shaved": 20665, + "232": 20666, + "currie": 20667, + "##ush": 20668, + "dharma": 20669, + "spartan": 20670, + "##ooped": 20671, + "favorites": 20672, + "smug": 20673, + "novella": 20674, + "sirens": 20675, + "abusive": 20676, + "creations": 20677, + "espana": 20678, + "##lage": 20679, + "paradigm": 20680, + "semiconductor": 20681, + "sheen": 20682, + "##rdo": 20683, + "##yen": 20684, + "##zak": 20685, + "nrl": 20686, + "renew": 20687, + "##pose": 20688, + "##tur": 20689, + "adjutant": 20690, + "marches": 20691, + "norma": 20692, + "##enity": 20693, + "ineffective": 20694, + "weimar": 20695, + "grunt": 20696, + "##gat": 20697, + "lordship": 20698, + "plotting": 20699, + "expenditure": 20700, + "infringement": 20701, + "lbs": 20702, + "refrain": 20703, + "av": 20704, + "mimi": 20705, + "mistakenly": 20706, + "postmaster": 20707, + "1771": 20708, + "##bara": 20709, + "ras": 20710, + "motorsports": 20711, + "tito": 20712, + "199": 20713, + "subjective": 20714, + "##zza": 20715, + "bully": 20716, + "stew": 20717, + "##kaya": 20718, + "prescott": 20719, + "1a": 20720, + "##raphic": 20721, + "##zam": 20722, + "bids": 20723, + "styling": 20724, + "paranormal": 20725, + "reeve": 20726, + "sneaking": 20727, + "exploding": 20728, + "katz": 20729, + "akbar": 20730, + "migrant": 20731, + "syllables": 20732, + "indefinitely": 20733, + "##ogical": 20734, + "destroys": 20735, + "replaces": 20736, + "applause": 20737, + "##phine": 20738, + "pest": 20739, + "##fide": 20740, + "218": 20741, + "articulated": 20742, + "bertie": 20743, + "##thing": 20744, + "##cars": 20745, + "##ptic": 20746, + "courtroom": 20747, + "crowley": 20748, + "aesthetics": 20749, + "cummings": 20750, + "tehsil": 20751, + "hormones": 20752, + "titanic": 20753, + "dangerously": 20754, + "##ibe": 20755, + "stadion": 20756, + "jaenelle": 20757, + "auguste": 20758, + "ciudad": 20759, + "##chu": 20760, + "mysore": 20761, + "partisans": 20762, + "##sio": 20763, + "lucan": 20764, + "philipp": 20765, + "##aly": 20766, + "debating": 20767, + "henley": 20768, + "interiors": 20769, + "##rano": 20770, + "##tious": 20771, + "homecoming": 20772, + "beyonce": 20773, + "usher": 20774, + "henrietta": 20775, + "prepares": 20776, + "weeds": 20777, + "##oman": 20778, + "ely": 20779, + "plucked": 20780, + "##pire": 20781, + "##dable": 20782, + "luxurious": 20783, + "##aq": 20784, + "artifact": 20785, + "password": 20786, + "pasture": 20787, + "juno": 20788, + "maddy": 20789, + "minsk": 20790, + "##dder": 20791, + "##ologies": 20792, + "##rone": 20793, + "assessments": 20794, + "martian": 20795, + "royalist": 20796, + "1765": 20797, + "examines": 20798, + "##mani": 20799, + "##rge": 20800, + "nino": 20801, + "223": 20802, + "parry": 20803, + "scooped": 20804, + "relativity": 20805, + "##eli": 20806, + "##uting": 20807, + "##cao": 20808, + "congregational": 20809, + "noisy": 20810, + "traverse": 20811, + "##agawa": 20812, + "strikeouts": 20813, + "nickelodeon": 20814, + "obituary": 20815, + "transylvania": 20816, + "binds": 20817, + "depictions": 20818, + "polk": 20819, + "trolley": 20820, + "##yed": 20821, + "##lard": 20822, + "breeders": 20823, + "##under": 20824, + "dryly": 20825, + "hokkaido": 20826, + "1762": 20827, + "strengths": 20828, + "stacks": 20829, + "bonaparte": 20830, + "connectivity": 20831, + "neared": 20832, + "prostitutes": 20833, + "stamped": 20834, + "anaheim": 20835, + "gutierrez": 20836, + "sinai": 20837, + "##zzling": 20838, + "bram": 20839, + "fresno": 20840, + "madhya": 20841, + "##86": 20842, + "proton": 20843, + "##lena": 20844, + "##llum": 20845, + "##phon": 20846, + "reelected": 20847, + "wanda": 20848, + "##anus": 20849, + "##lb": 20850, + "ample": 20851, + "distinguishing": 20852, + "##yler": 20853, + "grasping": 20854, + "sermons": 20855, + "tomato": 20856, + "bland": 20857, + "stimulation": 20858, + "avenues": 20859, + "##eux": 20860, + "spreads": 20861, + "scarlett": 20862, + "fern": 20863, + "pentagon": 20864, + "assert": 20865, + "baird": 20866, + "chesapeake": 20867, + "ir": 20868, + "calmed": 20869, + "distortion": 20870, + "fatalities": 20871, + "##olis": 20872, + "correctional": 20873, + "pricing": 20874, + "##astic": 20875, + "##gina": 20876, + "prom": 20877, + "dammit": 20878, + "ying": 20879, + "collaborate": 20880, + "##chia": 20881, + "welterweight": 20882, + "33rd": 20883, + "pointer": 20884, + "substitution": 20885, + "bonded": 20886, + "umpire": 20887, + "communicating": 20888, + "multitude": 20889, + "paddle": 20890, + "##obe": 20891, + "federally": 20892, + "intimacy": 20893, + "##insky": 20894, + "betray": 20895, + "ssr": 20896, + "##lett": 20897, + "##lean": 20898, + "##lves": 20899, + "##therapy": 20900, + "airbus": 20901, + "##tery": 20902, + "functioned": 20903, + "ud": 20904, + "bearer": 20905, + "biomedical": 20906, + "netflix": 20907, + "##hire": 20908, + "##nca": 20909, + "condom": 20910, + "brink": 20911, + "ik": 20912, + "##nical": 20913, + "macy": 20914, + "##bet": 20915, + "flap": 20916, + "gma": 20917, + "experimented": 20918, + "jelly": 20919, + "lavender": 20920, + "##icles": 20921, + "##ulia": 20922, + "munro": 20923, + "##mian": 20924, + "##tial": 20925, + "rye": 20926, + "##rle": 20927, + "60th": 20928, + "gigs": 20929, + "hottest": 20930, + "rotated": 20931, + "predictions": 20932, + "fuji": 20933, + "bu": 20934, + "##erence": 20935, + "##omi": 20936, + "barangay": 20937, + "##fulness": 20938, + "##sas": 20939, + "clocks": 20940, + "##rwood": 20941, + "##liness": 20942, + "cereal": 20943, + "roe": 20944, + "wight": 20945, + "decker": 20946, + "uttered": 20947, + "babu": 20948, + "onion": 20949, + "xml": 20950, + "forcibly": 20951, + "##df": 20952, + "petra": 20953, + "sarcasm": 20954, + "hartley": 20955, + "peeled": 20956, + "storytelling": 20957, + "##42": 20958, + "##xley": 20959, + "##ysis": 20960, + "##ffa": 20961, + "fibre": 20962, + "kiel": 20963, + "auditor": 20964, + "fig": 20965, + "harald": 20966, + "greenville": 20967, + "##berries": 20968, + "geographically": 20969, + "nell": 20970, + "quartz": 20971, + "##athic": 20972, + "cemeteries": 20973, + "##lr": 20974, + "crossings": 20975, + "nah": 20976, + "holloway": 20977, + "reptiles": 20978, + "chun": 20979, + "sichuan": 20980, + "snowy": 20981, + "660": 20982, + "corrections": 20983, + "##ivo": 20984, + "zheng": 20985, + "ambassadors": 20986, + "blacksmith": 20987, + "fielded": 20988, + "fluids": 20989, + "hardcover": 20990, + "turnover": 20991, + "medications": 20992, + "melvin": 20993, + "academies": 20994, + "##erton": 20995, + "ro": 20996, + "roach": 20997, + "absorbing": 20998, + "spaniards": 20999, + "colton": 21000, + "##founded": 21001, + "outsider": 21002, + "espionage": 21003, + "kelsey": 21004, + "245": 21005, + "edible": 21006, + "##ulf": 21007, + "dora": 21008, + "establishes": 21009, + "##sham": 21010, + "##tries": 21011, + "contracting": 21012, + "##tania": 21013, + "cinematic": 21014, + "costello": 21015, + "nesting": 21016, + "##uron": 21017, + "connolly": 21018, + "duff": 21019, + "##nology": 21020, + "mma": 21021, + "##mata": 21022, + "fergus": 21023, + "sexes": 21024, + "gi": 21025, + "optics": 21026, + "spectator": 21027, + "woodstock": 21028, + "banning": 21029, + "##hee": 21030, + "##fle": 21031, + "differentiate": 21032, + "outfielder": 21033, + "refinery": 21034, + "226": 21035, + "312": 21036, + "gerhard": 21037, + "horde": 21038, + "lair": 21039, + "drastically": 21040, + "##udi": 21041, + "landfall": 21042, + "##cheng": 21043, + "motorsport": 21044, + "odi": 21045, + "##achi": 21046, + "predominant": 21047, + "quay": 21048, + "skins": 21049, + "##ental": 21050, + "edna": 21051, + "harshly": 21052, + "complementary": 21053, + "murdering": 21054, + "##aves": 21055, + "wreckage": 21056, + "##90": 21057, + "ono": 21058, + "outstretched": 21059, + "lennox": 21060, + "munitions": 21061, + "galen": 21062, + "reconcile": 21063, + "470": 21064, + "scalp": 21065, + "bicycles": 21066, + "gillespie": 21067, + "questionable": 21068, + "rosenberg": 21069, + "guillermo": 21070, + "hostel": 21071, + "jarvis": 21072, + "kabul": 21073, + "volvo": 21074, + "opium": 21075, + "yd": 21076, + "##twined": 21077, + "abuses": 21078, + "decca": 21079, + "outpost": 21080, + "##cino": 21081, + "sensible": 21082, + "neutrality": 21083, + "##64": 21084, + "ponce": 21085, + "anchorage": 21086, + "atkins": 21087, + "turrets": 21088, + "inadvertently": 21089, + "disagree": 21090, + "libre": 21091, + "vodka": 21092, + "reassuring": 21093, + "weighs": 21094, + "##yal": 21095, + "glide": 21096, + "jumper": 21097, + "ceilings": 21098, + "repertory": 21099, + "outs": 21100, + "stain": 21101, + "##bial": 21102, + "envy": 21103, + "##ucible": 21104, + "smashing": 21105, + "heightened": 21106, + "policing": 21107, + "hyun": 21108, + "mixes": 21109, + "lai": 21110, + "prima": 21111, + "##ples": 21112, + "celeste": 21113, + "##bina": 21114, + "lucrative": 21115, + "intervened": 21116, + "kc": 21117, + "manually": 21118, + "##rned": 21119, + "stature": 21120, + "staffed": 21121, + "bun": 21122, + "bastards": 21123, + "nairobi": 21124, + "priced": 21125, + "##auer": 21126, + "thatcher": 21127, + "##kia": 21128, + "tripped": 21129, + "comune": 21130, + "##ogan": 21131, + "##pled": 21132, + "brasil": 21133, + "incentives": 21134, + "emanuel": 21135, + "hereford": 21136, + "musica": 21137, + "##kim": 21138, + "benedictine": 21139, + "biennale": 21140, + "##lani": 21141, + "eureka": 21142, + "gardiner": 21143, + "rb": 21144, + "knocks": 21145, + "sha": 21146, + "##ael": 21147, + "##elled": 21148, + "##onate": 21149, + "efficacy": 21150, + "ventura": 21151, + "masonic": 21152, + "sanford": 21153, + "maize": 21154, + "leverage": 21155, + "##feit": 21156, + "capacities": 21157, + "santana": 21158, + "##aur": 21159, + "novelty": 21160, + "vanilla": 21161, + "##cter": 21162, + "##tour": 21163, + "benin": 21164, + "##oir": 21165, + "##rain": 21166, + "neptune": 21167, + "drafting": 21168, + "tallinn": 21169, + "##cable": 21170, + "humiliation": 21171, + "##boarding": 21172, + "schleswig": 21173, + "fabian": 21174, + "bernardo": 21175, + "liturgy": 21176, + "spectacle": 21177, + "sweeney": 21178, + "pont": 21179, + "routledge": 21180, + "##tment": 21181, + "cosmos": 21182, + "ut": 21183, + "hilt": 21184, + "sleek": 21185, + "universally": 21186, + "##eville": 21187, + "##gawa": 21188, + "typed": 21189, + "##dry": 21190, + "favors": 21191, + "allegheny": 21192, + "glaciers": 21193, + "##rly": 21194, + "recalling": 21195, + "aziz": 21196, + "##log": 21197, + "parasite": 21198, + "requiem": 21199, + "auf": 21200, + "##berto": 21201, + "##llin": 21202, + "illumination": 21203, + "##breaker": 21204, + "##issa": 21205, + "festivities": 21206, + "bows": 21207, + "govern": 21208, + "vibe": 21209, + "vp": 21210, + "333": 21211, + "sprawled": 21212, + "larson": 21213, + "pilgrim": 21214, + "bwf": 21215, + "leaping": 21216, + "##rts": 21217, + "##ssel": 21218, + "alexei": 21219, + "greyhound": 21220, + "hoarse": 21221, + "##dler": 21222, + "##oration": 21223, + "seneca": 21224, + "##cule": 21225, + "gaping": 21226, + "##ulously": 21227, + "##pura": 21228, + "cinnamon": 21229, + "##gens": 21230, + "##rricular": 21231, + "craven": 21232, + "fantasies": 21233, + "houghton": 21234, + "engined": 21235, + "reigned": 21236, + "dictator": 21237, + "supervising": 21238, + "##oris": 21239, + "bogota": 21240, + "commentaries": 21241, + "unnatural": 21242, + "fingernails": 21243, + "spirituality": 21244, + "tighten": 21245, + "##tm": 21246, + "canadiens": 21247, + "protesting": 21248, + "intentional": 21249, + "cheers": 21250, + "sparta": 21251, + "##ytic": 21252, + "##iere": 21253, + "##zine": 21254, + "widen": 21255, + "belgarath": 21256, + "controllers": 21257, + "dodd": 21258, + "iaaf": 21259, + "navarre": 21260, + "##ication": 21261, + "defect": 21262, + "squire": 21263, + "steiner": 21264, + "whisky": 21265, + "##mins": 21266, + "560": 21267, + "inevitably": 21268, + "tome": 21269, + "##gold": 21270, + "chew": 21271, + "##uid": 21272, + "##lid": 21273, + "elastic": 21274, + "##aby": 21275, + "streaked": 21276, + "alliances": 21277, + "jailed": 21278, + "regal": 21279, + "##ined": 21280, + "##phy": 21281, + "czechoslovak": 21282, + "narration": 21283, + "absently": 21284, + "##uld": 21285, + "bluegrass": 21286, + "guangdong": 21287, + "quran": 21288, + "criticizing": 21289, + "hose": 21290, + "hari": 21291, + "##liest": 21292, + "##owa": 21293, + "skier": 21294, + "streaks": 21295, + "deploy": 21296, + "##lom": 21297, + "raft": 21298, + "bose": 21299, + "dialed": 21300, + "huff": 21301, + "##eira": 21302, + "haifa": 21303, + "simplest": 21304, + "bursting": 21305, + "endings": 21306, + "ib": 21307, + "sultanate": 21308, + "##titled": 21309, + "franks": 21310, + "whitman": 21311, + "ensures": 21312, + "sven": 21313, + "##ggs": 21314, + "collaborators": 21315, + "forster": 21316, + "organising": 21317, + "ui": 21318, + "banished": 21319, + "napier": 21320, + "injustice": 21321, + "teller": 21322, + "layered": 21323, + "thump": 21324, + "##otti": 21325, + "roc": 21326, + "battleships": 21327, + "evidenced": 21328, + "fugitive": 21329, + "sadie": 21330, + "robotics": 21331, + "##roud": 21332, + "equatorial": 21333, + "geologist": 21334, + "##iza": 21335, + "yielding": 21336, + "##bron": 21337, + "##sr": 21338, + "internationale": 21339, + "mecca": 21340, + "##diment": 21341, + "sbs": 21342, + "skyline": 21343, + "toad": 21344, + "uploaded": 21345, + "reflective": 21346, + "undrafted": 21347, + "lal": 21348, + "leafs": 21349, + "bayern": 21350, + "##dai": 21351, + "lakshmi": 21352, + "shortlisted": 21353, + "##stick": 21354, + "##wicz": 21355, + "camouflage": 21356, + "donate": 21357, + "af": 21358, + "christi": 21359, + "lau": 21360, + "##acio": 21361, + "disclosed": 21362, + "nemesis": 21363, + "1761": 21364, + "assemble": 21365, + "straining": 21366, + "northamptonshire": 21367, + "tal": 21368, + "##asi": 21369, + "bernardino": 21370, + "premature": 21371, + "heidi": 21372, + "42nd": 21373, + "coefficients": 21374, + "galactic": 21375, + "reproduce": 21376, + "buzzed": 21377, + "sensations": 21378, + "zionist": 21379, + "monsieur": 21380, + "myrtle": 21381, + "##eme": 21382, + "archery": 21383, + "strangled": 21384, + "musically": 21385, + "viewpoint": 21386, + "antiquities": 21387, + "bei": 21388, + "trailers": 21389, + "seahawks": 21390, + "cured": 21391, + "pee": 21392, + "preferring": 21393, + "tasmanian": 21394, + "lange": 21395, + "sul": 21396, + "##mail": 21397, + "##working": 21398, + "colder": 21399, + "overland": 21400, + "lucivar": 21401, + "massey": 21402, + "gatherings": 21403, + "haitian": 21404, + "##smith": 21405, + "disapproval": 21406, + "flaws": 21407, + "##cco": 21408, + "##enbach": 21409, + "1766": 21410, + "npr": 21411, + "##icular": 21412, + "boroughs": 21413, + "creole": 21414, + "forums": 21415, + "techno": 21416, + "1755": 21417, + "dent": 21418, + "abdominal": 21419, + "streetcar": 21420, + "##eson": 21421, + "##stream": 21422, + "procurement": 21423, + "gemini": 21424, + "predictable": 21425, + "##tya": 21426, + "acheron": 21427, + "christoph": 21428, + "feeder": 21429, + "fronts": 21430, + "vendor": 21431, + "bernhard": 21432, + "jammu": 21433, + "tumors": 21434, + "slang": 21435, + "##uber": 21436, + "goaltender": 21437, + "twists": 21438, + "curving": 21439, + "manson": 21440, + "vuelta": 21441, + "mer": 21442, + "peanut": 21443, + "confessions": 21444, + "pouch": 21445, + "unpredictable": 21446, + "allowance": 21447, + "theodor": 21448, + "vascular": 21449, + "##factory": 21450, + "bala": 21451, + "authenticity": 21452, + "metabolic": 21453, + "coughing": 21454, + "nanjing": 21455, + "##cea": 21456, + "pembroke": 21457, + "##bard": 21458, + "splendid": 21459, + "36th": 21460, + "ff": 21461, + "hourly": 21462, + "##ahu": 21463, + "elmer": 21464, + "handel": 21465, + "##ivate": 21466, + "awarding": 21467, + "thrusting": 21468, + "dl": 21469, + "experimentation": 21470, + "##hesion": 21471, + "##46": 21472, + "caressed": 21473, + "entertained": 21474, + "steak": 21475, + "##rangle": 21476, + "biologist": 21477, + "orphans": 21478, + "baroness": 21479, + "oyster": 21480, + "stepfather": 21481, + "##dridge": 21482, + "mirage": 21483, + "reefs": 21484, + "speeding": 21485, + "##31": 21486, + "barons": 21487, + "1764": 21488, + "227": 21489, + "inhabit": 21490, + "preached": 21491, + "repealed": 21492, + "##tral": 21493, + "honoring": 21494, + "boogie": 21495, + "captives": 21496, + "administer": 21497, + "johanna": 21498, + "##imate": 21499, + "gel": 21500, + "suspiciously": 21501, + "1767": 21502, + "sobs": 21503, + "##dington": 21504, + "backbone": 21505, + "hayward": 21506, + "garry": 21507, + "##folding": 21508, + "##nesia": 21509, + "maxi": 21510, + "##oof": 21511, + "##ppe": 21512, + "ellison": 21513, + "galileo": 21514, + "##stand": 21515, + "crimea": 21516, + "frenzy": 21517, + "amour": 21518, + "bumper": 21519, + "matrices": 21520, + "natalia": 21521, + "baking": 21522, + "garth": 21523, + "palestinians": 21524, + "##grove": 21525, + "smack": 21526, + "conveyed": 21527, + "ensembles": 21528, + "gardening": 21529, + "##manship": 21530, + "##rup": 21531, + "##stituting": 21532, + "1640": 21533, + "harvesting": 21534, + "topography": 21535, + "jing": 21536, + "shifters": 21537, + "dormitory": 21538, + "##carriage": 21539, + "##lston": 21540, + "ist": 21541, + "skulls": 21542, + "##stadt": 21543, + "dolores": 21544, + "jewellery": 21545, + "sarawak": 21546, + "##wai": 21547, + "##zier": 21548, + "fences": 21549, + "christy": 21550, + "confinement": 21551, + "tumbling": 21552, + "credibility": 21553, + "fir": 21554, + "stench": 21555, + "##bria": 21556, + "##plication": 21557, + "##nged": 21558, + "##sam": 21559, + "virtues": 21560, + "##belt": 21561, + "marjorie": 21562, + "pba": 21563, + "##eem": 21564, + "##made": 21565, + "celebrates": 21566, + "schooner": 21567, + "agitated": 21568, + "barley": 21569, + "fulfilling": 21570, + "anthropologist": 21571, + "##pro": 21572, + "restrict": 21573, + "novi": 21574, + "regulating": 21575, + "##nent": 21576, + "padres": 21577, + "##rani": 21578, + "##hesive": 21579, + "loyola": 21580, + "tabitha": 21581, + "milky": 21582, + "olson": 21583, + "proprietor": 21584, + "crambidae": 21585, + "guarantees": 21586, + "intercollegiate": 21587, + "ljubljana": 21588, + "hilda": 21589, + "##sko": 21590, + "ignorant": 21591, + "hooded": 21592, + "##lts": 21593, + "sardinia": 21594, + "##lidae": 21595, + "##vation": 21596, + "frontman": 21597, + "privileged": 21598, + "witchcraft": 21599, + "##gp": 21600, + "jammed": 21601, + "laude": 21602, + "poking": 21603, + "##than": 21604, + "bracket": 21605, + "amazement": 21606, + "yunnan": 21607, + "##erus": 21608, + "maharaja": 21609, + "linnaeus": 21610, + "264": 21611, + "commissioning": 21612, + "milano": 21613, + "peacefully": 21614, + "##logies": 21615, + "akira": 21616, + "rani": 21617, + "regulator": 21618, + "##36": 21619, + "grasses": 21620, + "##rance": 21621, + "luzon": 21622, + "crows": 21623, + "compiler": 21624, + "gretchen": 21625, + "seaman": 21626, + "edouard": 21627, + "tab": 21628, + "buccaneers": 21629, + "ellington": 21630, + "hamlets": 21631, + "whig": 21632, + "socialists": 21633, + "##anto": 21634, + "directorial": 21635, + "easton": 21636, + "mythological": 21637, + "##kr": 21638, + "##vary": 21639, + "rhineland": 21640, + "semantic": 21641, + "taut": 21642, + "dune": 21643, + "inventions": 21644, + "succeeds": 21645, + "##iter": 21646, + "replication": 21647, + "branched": 21648, + "##pired": 21649, + "jul": 21650, + "prosecuted": 21651, + "kangaroo": 21652, + "penetrated": 21653, + "##avian": 21654, + "middlesbrough": 21655, + "doses": 21656, + "bleak": 21657, + "madam": 21658, + "predatory": 21659, + "relentless": 21660, + "##vili": 21661, + "reluctance": 21662, + "##vir": 21663, + "hailey": 21664, + "crore": 21665, + "silvery": 21666, + "1759": 21667, + "monstrous": 21668, + "swimmers": 21669, + "transmissions": 21670, + "hawthorn": 21671, + "informing": 21672, + "##eral": 21673, + "toilets": 21674, + "caracas": 21675, + "crouch": 21676, + "kb": 21677, + "##sett": 21678, + "295": 21679, + "cartel": 21680, + "hadley": 21681, + "##aling": 21682, + "alexia": 21683, + "yvonne": 21684, + "##biology": 21685, + "cinderella": 21686, + "eton": 21687, + "superb": 21688, + "blizzard": 21689, + "stabbing": 21690, + "industrialist": 21691, + "maximus": 21692, + "##gm": 21693, + "##orus": 21694, + "groves": 21695, + "maud": 21696, + "clade": 21697, + "oversized": 21698, + "comedic": 21699, + "##bella": 21700, + "rosen": 21701, + "nomadic": 21702, + "fulham": 21703, + "montane": 21704, + "beverages": 21705, + "galaxies": 21706, + "redundant": 21707, + "swarm": 21708, + "##rot": 21709, + "##folia": 21710, + "##llis": 21711, + "buckinghamshire": 21712, + "fen": 21713, + "bearings": 21714, + "bahadur": 21715, + "##rom": 21716, + "gilles": 21717, + "phased": 21718, + "dynamite": 21719, + "faber": 21720, + "benoit": 21721, + "vip": 21722, + "##ount": 21723, + "##wd": 21724, + "booking": 21725, + "fractured": 21726, + "tailored": 21727, + "anya": 21728, + "spices": 21729, + "westwood": 21730, + "cairns": 21731, + "auditions": 21732, + "inflammation": 21733, + "steamed": 21734, + "##rocity": 21735, + "##acion": 21736, + "##urne": 21737, + "skyla": 21738, + "thereof": 21739, + "watford": 21740, + "torment": 21741, + "archdeacon": 21742, + "transforms": 21743, + "lulu": 21744, + "demeanor": 21745, + "fucked": 21746, + "serge": 21747, + "##sor": 21748, + "mckenna": 21749, + "minas": 21750, + "entertainer": 21751, + "##icide": 21752, + "caress": 21753, + "originate": 21754, + "residue": 21755, + "##sty": 21756, + "1740": 21757, + "##ilised": 21758, + "##org": 21759, + "beech": 21760, + "##wana": 21761, + "subsidies": 21762, + "##ghton": 21763, + "emptied": 21764, + "gladstone": 21765, + "ru": 21766, + "firefighters": 21767, + "voodoo": 21768, + "##rcle": 21769, + "het": 21770, + "nightingale": 21771, + "tamara": 21772, + "edmond": 21773, + "ingredient": 21774, + "weaknesses": 21775, + "silhouette": 21776, + "285": 21777, + "compatibility": 21778, + "withdrawing": 21779, + "hampson": 21780, + "##mona": 21781, + "anguish": 21782, + "giggling": 21783, + "##mber": 21784, + "bookstore": 21785, + "##jiang": 21786, + "southernmost": 21787, + "tilting": 21788, + "##vance": 21789, + "bai": 21790, + "economical": 21791, + "rf": 21792, + "briefcase": 21793, + "dreadful": 21794, + "hinted": 21795, + "projections": 21796, + "shattering": 21797, + "totaling": 21798, + "##rogate": 21799, + "analogue": 21800, + "indicted": 21801, + "periodical": 21802, + "fullback": 21803, + "##dman": 21804, + "haynes": 21805, + "##tenberg": 21806, + "##ffs": 21807, + "##ishment": 21808, + "1745": 21809, + "thirst": 21810, + "stumble": 21811, + "penang": 21812, + "vigorous": 21813, + "##ddling": 21814, + "##kor": 21815, + "##lium": 21816, + "octave": 21817, + "##ove": 21818, + "##enstein": 21819, + "##inen": 21820, + "##ones": 21821, + "siberian": 21822, + "##uti": 21823, + "cbn": 21824, + "repeal": 21825, + "swaying": 21826, + "##vington": 21827, + "khalid": 21828, + "tanaka": 21829, + "unicorn": 21830, + "otago": 21831, + "plastered": 21832, + "lobe": 21833, + "riddle": 21834, + "##rella": 21835, + "perch": 21836, + "##ishing": 21837, + "croydon": 21838, + "filtered": 21839, + "graeme": 21840, + "tripoli": 21841, + "##ossa": 21842, + "crocodile": 21843, + "##chers": 21844, + "sufi": 21845, + "mined": 21846, + "##tung": 21847, + "inferno": 21848, + "lsu": 21849, + "##phi": 21850, + "swelled": 21851, + "utilizes": 21852, + "£2": 21853, + "cale": 21854, + "periodicals": 21855, + "styx": 21856, + "hike": 21857, + "informally": 21858, + "coop": 21859, + "lund": 21860, + "##tidae": 21861, + "ala": 21862, + "hen": 21863, + "qui": 21864, + "transformations": 21865, + "disposed": 21866, + "sheath": 21867, + "chickens": 21868, + "##cade": 21869, + "fitzroy": 21870, + "sas": 21871, + "silesia": 21872, + "unacceptable": 21873, + "odisha": 21874, + "1650": 21875, + "sabrina": 21876, + "pe": 21877, + "spokane": 21878, + "ratios": 21879, + "athena": 21880, + "massage": 21881, + "shen": 21882, + "dilemma": 21883, + "##drum": 21884, + "##riz": 21885, + "##hul": 21886, + "corona": 21887, + "doubtful": 21888, + "niall": 21889, + "##pha": 21890, + "##bino": 21891, + "fines": 21892, + "cite": 21893, + "acknowledging": 21894, + "bangor": 21895, + "ballard": 21896, + "bathurst": 21897, + "##resh": 21898, + "huron": 21899, + "mustered": 21900, + "alzheimer": 21901, + "garments": 21902, + "kinase": 21903, + "tyre": 21904, + "warship": 21905, + "##cp": 21906, + "flashback": 21907, + "pulmonary": 21908, + "braun": 21909, + "cheat": 21910, + "kamal": 21911, + "cyclists": 21912, + "constructions": 21913, + "grenades": 21914, + "ndp": 21915, + "traveller": 21916, + "excuses": 21917, + "stomped": 21918, + "signalling": 21919, + "trimmed": 21920, + "futsal": 21921, + "mosques": 21922, + "relevance": 21923, + "##wine": 21924, + "wta": 21925, + "##23": 21926, + "##vah": 21927, + "##lter": 21928, + "hoc": 21929, + "##riding": 21930, + "optimistic": 21931, + "##´s": 21932, + "deco": 21933, + "sim": 21934, + "interacting": 21935, + "rejecting": 21936, + "moniker": 21937, + "waterways": 21938, + "##ieri": 21939, + "##oku": 21940, + "mayors": 21941, + "gdansk": 21942, + "outnumbered": 21943, + "pearls": 21944, + "##ended": 21945, + "##hampton": 21946, + "fairs": 21947, + "totals": 21948, + "dominating": 21949, + "262": 21950, + "notions": 21951, + "stairway": 21952, + "compiling": 21953, + "pursed": 21954, + "commodities": 21955, + "grease": 21956, + "yeast": 21957, + "##jong": 21958, + "carthage": 21959, + "griffiths": 21960, + "residual": 21961, + "amc": 21962, + "contraction": 21963, + "laird": 21964, + "sapphire": 21965, + "##marine": 21966, + "##ivated": 21967, + "amalgamation": 21968, + "dissolve": 21969, + "inclination": 21970, + "lyle": 21971, + "packaged": 21972, + "altitudes": 21973, + "suez": 21974, + "canons": 21975, + "graded": 21976, + "lurched": 21977, + "narrowing": 21978, + "boasts": 21979, + "guise": 21980, + "wed": 21981, + "enrico": 21982, + "##ovsky": 21983, + "rower": 21984, + "scarred": 21985, + "bree": 21986, + "cub": 21987, + "iberian": 21988, + "protagonists": 21989, + "bargaining": 21990, + "proposing": 21991, + "trainers": 21992, + "voyages": 21993, + "vans": 21994, + "fishes": 21995, + "##aea": 21996, + "##ivist": 21997, + "##verance": 21998, + "encryption": 21999, + "artworks": 22000, + "kazan": 22001, + "sabre": 22002, + "cleopatra": 22003, + "hepburn": 22004, + "rotting": 22005, + "supremacy": 22006, + "mecklenburg": 22007, + "##brate": 22008, + "burrows": 22009, + "hazards": 22010, + "outgoing": 22011, + "flair": 22012, + "organizes": 22013, + "##ctions": 22014, + "scorpion": 22015, + "##usions": 22016, + "boo": 22017, + "234": 22018, + "chevalier": 22019, + "dunedin": 22020, + "slapping": 22021, + "##34": 22022, + "ineligible": 22023, + "pensions": 22024, + "##38": 22025, + "##omic": 22026, + "manufactures": 22027, + "emails": 22028, + "bismarck": 22029, + "238": 22030, + "weakening": 22031, + "blackish": 22032, + "ding": 22033, + "mcgee": 22034, + "quo": 22035, + "##rling": 22036, + "northernmost": 22037, + "xx": 22038, + "manpower": 22039, + "greed": 22040, + "sampson": 22041, + "clicking": 22042, + "##ange": 22043, + "##horpe": 22044, + "##inations": 22045, + "##roving": 22046, + "torre": 22047, + "##eptive": 22048, + "##moral": 22049, + "symbolism": 22050, + "38th": 22051, + "asshole": 22052, + "meritorious": 22053, + "outfits": 22054, + "splashed": 22055, + "biographies": 22056, + "sprung": 22057, + "astros": 22058, + "##tale": 22059, + "302": 22060, + "737": 22061, + "filly": 22062, + "raoul": 22063, + "nw": 22064, + "tokugawa": 22065, + "linden": 22066, + "clubhouse": 22067, + "##apa": 22068, + "tracts": 22069, + "romano": 22070, + "##pio": 22071, + "putin": 22072, + "tags": 22073, + "##note": 22074, + "chained": 22075, + "dickson": 22076, + "gunshot": 22077, + "moe": 22078, + "gunn": 22079, + "rashid": 22080, + "##tails": 22081, + "zipper": 22082, + "##bas": 22083, + "##nea": 22084, + "contrasted": 22085, + "##ply": 22086, + "##udes": 22087, + "plum": 22088, + "pharaoh": 22089, + "##pile": 22090, + "aw": 22091, + "comedies": 22092, + "ingrid": 22093, + "sandwiches": 22094, + "subdivisions": 22095, + "1100": 22096, + "mariana": 22097, + "nokia": 22098, + "kamen": 22099, + "hz": 22100, + "delaney": 22101, + "veto": 22102, + "herring": 22103, + "##words": 22104, + "possessive": 22105, + "outlines": 22106, + "##roup": 22107, + "siemens": 22108, + "stairwell": 22109, + "rc": 22110, + "gallantry": 22111, + "messiah": 22112, + "palais": 22113, + "yells": 22114, + "233": 22115, + "zeppelin": 22116, + "##dm": 22117, + "bolivar": 22118, + "##cede": 22119, + "smackdown": 22120, + "mckinley": 22121, + "##mora": 22122, + "##yt": 22123, + "muted": 22124, + "geologic": 22125, + "finely": 22126, + "unitary": 22127, + "avatar": 22128, + "hamas": 22129, + "maynard": 22130, + "rees": 22131, + "bog": 22132, + "contrasting": 22133, + "##rut": 22134, + "liv": 22135, + "chico": 22136, + "disposition": 22137, + "pixel": 22138, + "##erate": 22139, + "becca": 22140, + "dmitry": 22141, + "yeshiva": 22142, + "narratives": 22143, + "##lva": 22144, + "##ulton": 22145, + "mercenary": 22146, + "sharpe": 22147, + "tempered": 22148, + "navigate": 22149, + "stealth": 22150, + "amassed": 22151, + "keynes": 22152, + "##lini": 22153, + "untouched": 22154, + "##rrie": 22155, + "havoc": 22156, + "lithium": 22157, + "##fighting": 22158, + "abyss": 22159, + "graf": 22160, + "southward": 22161, + "wolverine": 22162, + "balloons": 22163, + "implements": 22164, + "ngos": 22165, + "transitions": 22166, + "##icum": 22167, + "ambushed": 22168, + "concacaf": 22169, + "dormant": 22170, + "economists": 22171, + "##dim": 22172, + "costing": 22173, + "csi": 22174, + "rana": 22175, + "universite": 22176, + "boulders": 22177, + "verity": 22178, + "##llon": 22179, + "collin": 22180, + "mellon": 22181, + "misses": 22182, + "cypress": 22183, + "fluorescent": 22184, + "lifeless": 22185, + "spence": 22186, + "##ulla": 22187, + "crewe": 22188, + "shepard": 22189, + "pak": 22190, + "revelations": 22191, + "##م": 22192, + "jolly": 22193, + "gibbons": 22194, + "paw": 22195, + "##dro": 22196, + "##quel": 22197, + "freeing": 22198, + "##test": 22199, + "shack": 22200, + "fries": 22201, + "palatine": 22202, + "##51": 22203, + "##hiko": 22204, + "accompaniment": 22205, + "cruising": 22206, + "recycled": 22207, + "##aver": 22208, + "erwin": 22209, + "sorting": 22210, + "synthesizers": 22211, + "dyke": 22212, + "realities": 22213, + "sg": 22214, + "strides": 22215, + "enslaved": 22216, + "wetland": 22217, + "##ghan": 22218, + "competence": 22219, + "gunpowder": 22220, + "grassy": 22221, + "maroon": 22222, + "reactors": 22223, + "objection": 22224, + "##oms": 22225, + "carlson": 22226, + "gearbox": 22227, + "macintosh": 22228, + "radios": 22229, + "shelton": 22230, + "##sho": 22231, + "clergyman": 22232, + "prakash": 22233, + "254": 22234, + "mongols": 22235, + "trophies": 22236, + "oricon": 22237, + "228": 22238, + "stimuli": 22239, + "twenty20": 22240, + "cantonese": 22241, + "cortes": 22242, + "mirrored": 22243, + "##saurus": 22244, + "bhp": 22245, + "cristina": 22246, + "melancholy": 22247, + "##lating": 22248, + "enjoyable": 22249, + "nuevo": 22250, + "##wny": 22251, + "downfall": 22252, + "schumacher": 22253, + "##ind": 22254, + "banging": 22255, + "lausanne": 22256, + "rumbled": 22257, + "paramilitary": 22258, + "reflex": 22259, + "ax": 22260, + "amplitude": 22261, + "migratory": 22262, + "##gall": 22263, + "##ups": 22264, + "midi": 22265, + "barnard": 22266, + "lastly": 22267, + "sherry": 22268, + "##hp": 22269, + "##nall": 22270, + "keystone": 22271, + "##kra": 22272, + "carleton": 22273, + "slippery": 22274, + "##53": 22275, + "coloring": 22276, + "foe": 22277, + "socket": 22278, + "otter": 22279, + "##rgos": 22280, + "mats": 22281, + "##tose": 22282, + "consultants": 22283, + "bafta": 22284, + "bison": 22285, + "topping": 22286, + "##km": 22287, + "490": 22288, + "primal": 22289, + "abandonment": 22290, + "transplant": 22291, + "atoll": 22292, + "hideous": 22293, + "mort": 22294, + "pained": 22295, + "reproduced": 22296, + "tae": 22297, + "howling": 22298, + "##turn": 22299, + "unlawful": 22300, + "billionaire": 22301, + "hotter": 22302, + "poised": 22303, + "lansing": 22304, + "##chang": 22305, + "dinamo": 22306, + "retro": 22307, + "messing": 22308, + "nfc": 22309, + "domesday": 22310, + "##mina": 22311, + "blitz": 22312, + "timed": 22313, + "##athing": 22314, + "##kley": 22315, + "ascending": 22316, + "gesturing": 22317, + "##izations": 22318, + "signaled": 22319, + "tis": 22320, + "chinatown": 22321, + "mermaid": 22322, + "savanna": 22323, + "jameson": 22324, + "##aint": 22325, + "catalina": 22326, + "##pet": 22327, + "##hers": 22328, + "cochrane": 22329, + "cy": 22330, + "chatting": 22331, + "##kus": 22332, + "alerted": 22333, + "computation": 22334, + "mused": 22335, + "noelle": 22336, + "majestic": 22337, + "mohawk": 22338, + "campo": 22339, + "octagonal": 22340, + "##sant": 22341, + "##hend": 22342, + "241": 22343, + "aspiring": 22344, + "##mart": 22345, + "comprehend": 22346, + "iona": 22347, + "paralyzed": 22348, + "shimmering": 22349, + "swindon": 22350, + "rhone": 22351, + "##eley": 22352, + "reputed": 22353, + "configurations": 22354, + "pitchfork": 22355, + "agitation": 22356, + "francais": 22357, + "gillian": 22358, + "lipstick": 22359, + "##ilo": 22360, + "outsiders": 22361, + "pontifical": 22362, + "resisting": 22363, + "bitterness": 22364, + "sewer": 22365, + "rockies": 22366, + "##edd": 22367, + "##ucher": 22368, + "misleading": 22369, + "1756": 22370, + "exiting": 22371, + "galloway": 22372, + "##nging": 22373, + "risked": 22374, + "##heart": 22375, + "246": 22376, + "commemoration": 22377, + "schultz": 22378, + "##rka": 22379, + "integrating": 22380, + "##rsa": 22381, + "poses": 22382, + "shrieked": 22383, + "##weiler": 22384, + "guineas": 22385, + "gladys": 22386, + "jerking": 22387, + "owls": 22388, + "goldsmith": 22389, + "nightly": 22390, + "penetrating": 22391, + "##unced": 22392, + "lia": 22393, + "##33": 22394, + "ignited": 22395, + "betsy": 22396, + "##aring": 22397, + "##thorpe": 22398, + "follower": 22399, + "vigorously": 22400, + "##rave": 22401, + "coded": 22402, + "kiran": 22403, + "knit": 22404, + "zoology": 22405, + "tbilisi": 22406, + "##28": 22407, + "##bered": 22408, + "repository": 22409, + "govt": 22410, + "deciduous": 22411, + "dino": 22412, + "growling": 22413, + "##bba": 22414, + "enhancement": 22415, + "unleashed": 22416, + "chanting": 22417, + "pussy": 22418, + "biochemistry": 22419, + "##eric": 22420, + "kettle": 22421, + "repression": 22422, + "toxicity": 22423, + "nrhp": 22424, + "##arth": 22425, + "##kko": 22426, + "##bush": 22427, + "ernesto": 22428, + "commended": 22429, + "outspoken": 22430, + "242": 22431, + "mca": 22432, + "parchment": 22433, + "sms": 22434, + "kristen": 22435, + "##aton": 22436, + "bisexual": 22437, + "raked": 22438, + "glamour": 22439, + "navajo": 22440, + "a2": 22441, + "conditioned": 22442, + "showcased": 22443, + "##hma": 22444, + "spacious": 22445, + "youthful": 22446, + "##esa": 22447, + "usl": 22448, + "appliances": 22449, + "junta": 22450, + "brest": 22451, + "layne": 22452, + "conglomerate": 22453, + "enchanted": 22454, + "chao": 22455, + "loosened": 22456, + "picasso": 22457, + "circulating": 22458, + "inspect": 22459, + "montevideo": 22460, + "##centric": 22461, + "##kti": 22462, + "piazza": 22463, + "spurred": 22464, + "##aith": 22465, + "bari": 22466, + "freedoms": 22467, + "poultry": 22468, + "stamford": 22469, + "lieu": 22470, + "##ect": 22471, + "indigo": 22472, + "sarcastic": 22473, + "bahia": 22474, + "stump": 22475, + "attach": 22476, + "dvds": 22477, + "frankenstein": 22478, + "lille": 22479, + "approx": 22480, + "scriptures": 22481, + "pollen": 22482, + "##script": 22483, + "nmi": 22484, + "overseen": 22485, + "##ivism": 22486, + "tides": 22487, + "proponent": 22488, + "newmarket": 22489, + "inherit": 22490, + "milling": 22491, + "##erland": 22492, + "centralized": 22493, + "##rou": 22494, + "distributors": 22495, + "credentials": 22496, + "drawers": 22497, + "abbreviation": 22498, + "##lco": 22499, + "##xon": 22500, + "downing": 22501, + "uncomfortably": 22502, + "ripe": 22503, + "##oes": 22504, + "erase": 22505, + "franchises": 22506, + "##ever": 22507, + "populace": 22508, + "##bery": 22509, + "##khar": 22510, + "decomposition": 22511, + "pleas": 22512, + "##tet": 22513, + "daryl": 22514, + "sabah": 22515, + "##stle": 22516, + "##wide": 22517, + "fearless": 22518, + "genie": 22519, + "lesions": 22520, + "annette": 22521, + "##ogist": 22522, + "oboe": 22523, + "appendix": 22524, + "nair": 22525, + "dripped": 22526, + "petitioned": 22527, + "maclean": 22528, + "mosquito": 22529, + "parrot": 22530, + "rpg": 22531, + "hampered": 22532, + "1648": 22533, + "operatic": 22534, + "reservoirs": 22535, + "##tham": 22536, + "irrelevant": 22537, + "jolt": 22538, + "summarized": 22539, + "##fp": 22540, + "medallion": 22541, + "##taff": 22542, + "##−": 22543, + "clawed": 22544, + "harlow": 22545, + "narrower": 22546, + "goddard": 22547, + "marcia": 22548, + "bodied": 22549, + "fremont": 22550, + "suarez": 22551, + "altering": 22552, + "tempest": 22553, + "mussolini": 22554, + "porn": 22555, + "##isms": 22556, + "sweetly": 22557, + "oversees": 22558, + "walkers": 22559, + "solitude": 22560, + "grimly": 22561, + "shrines": 22562, + "hk": 22563, + "ich": 22564, + "supervisors": 22565, + "hostess": 22566, + "dietrich": 22567, + "legitimacy": 22568, + "brushes": 22569, + "expressive": 22570, + "##yp": 22571, + "dissipated": 22572, + "##rse": 22573, + "localized": 22574, + "systemic": 22575, + "##nikov": 22576, + "gettysburg": 22577, + "##js": 22578, + "##uaries": 22579, + "dialogues": 22580, + "muttering": 22581, + "251": 22582, + "housekeeper": 22583, + "sicilian": 22584, + "discouraged": 22585, + "##frey": 22586, + "beamed": 22587, + "kaladin": 22588, + "halftime": 22589, + "kidnap": 22590, + "##amo": 22591, + "##llet": 22592, + "1754": 22593, + "synonymous": 22594, + "depleted": 22595, + "instituto": 22596, + "insulin": 22597, + "reprised": 22598, + "##opsis": 22599, + "clashed": 22600, + "##ctric": 22601, + "interrupting": 22602, + "radcliffe": 22603, + "insisting": 22604, + "medici": 22605, + "1715": 22606, + "ejected": 22607, + "playfully": 22608, + "turbulent": 22609, + "##47": 22610, + "starvation": 22611, + "##rini": 22612, + "shipment": 22613, + "rebellious": 22614, + "petersen": 22615, + "verification": 22616, + "merits": 22617, + "##rified": 22618, + "cakes": 22619, + "##charged": 22620, + "1757": 22621, + "milford": 22622, + "shortages": 22623, + "spying": 22624, + "fidelity": 22625, + "##aker": 22626, + "emitted": 22627, + "storylines": 22628, + "harvested": 22629, + "seismic": 22630, + "##iform": 22631, + "cheung": 22632, + "kilda": 22633, + "theoretically": 22634, + "barbie": 22635, + "lynx": 22636, + "##rgy": 22637, + "##tius": 22638, + "goblin": 22639, + "mata": 22640, + "poisonous": 22641, + "##nburg": 22642, + "reactive": 22643, + "residues": 22644, + "obedience": 22645, + "##евич": 22646, + "conjecture": 22647, + "##rac": 22648, + "401": 22649, + "hating": 22650, + "sixties": 22651, + "kicker": 22652, + "moaning": 22653, + "motown": 22654, + "##bha": 22655, + "emancipation": 22656, + "neoclassical": 22657, + "##hering": 22658, + "consoles": 22659, + "ebert": 22660, + "professorship": 22661, + "##tures": 22662, + "sustaining": 22663, + "assaults": 22664, + "obeyed": 22665, + "affluent": 22666, + "incurred": 22667, + "tornadoes": 22668, + "##eber": 22669, + "##zow": 22670, + "emphasizing": 22671, + "highlanders": 22672, + "cheated": 22673, + "helmets": 22674, + "##ctus": 22675, + "internship": 22676, + "terence": 22677, + "bony": 22678, + "executions": 22679, + "legislators": 22680, + "berries": 22681, + "peninsular": 22682, + "tinged": 22683, + "##aco": 22684, + "1689": 22685, + "amplifier": 22686, + "corvette": 22687, + "ribbons": 22688, + "lavish": 22689, + "pennant": 22690, + "##lander": 22691, + "worthless": 22692, + "##chfield": 22693, + "##forms": 22694, + "mariano": 22695, + "pyrenees": 22696, + "expenditures": 22697, + "##icides": 22698, + "chesterfield": 22699, + "mandir": 22700, + "tailor": 22701, + "39th": 22702, + "sergey": 22703, + "nestled": 22704, + "willed": 22705, + "aristocracy": 22706, + "devotees": 22707, + "goodnight": 22708, + "raaf": 22709, + "rumored": 22710, + "weaponry": 22711, + "remy": 22712, + "appropriations": 22713, + "harcourt": 22714, + "burr": 22715, + "riaa": 22716, + "##lence": 22717, + "limitation": 22718, + "unnoticed": 22719, + "guo": 22720, + "soaking": 22721, + "swamps": 22722, + "##tica": 22723, + "collapsing": 22724, + "tatiana": 22725, + "descriptive": 22726, + "brigham": 22727, + "psalm": 22728, + "##chment": 22729, + "maddox": 22730, + "##lization": 22731, + "patti": 22732, + "caliph": 22733, + "##aja": 22734, + "akron": 22735, + "injuring": 22736, + "serra": 22737, + "##ganj": 22738, + "basins": 22739, + "##sari": 22740, + "astonished": 22741, + "launcher": 22742, + "##church": 22743, + "hilary": 22744, + "wilkins": 22745, + "sewing": 22746, + "##sf": 22747, + "stinging": 22748, + "##fia": 22749, + "##ncia": 22750, + "underwood": 22751, + "startup": 22752, + "##ition": 22753, + "compilations": 22754, + "vibrations": 22755, + "embankment": 22756, + "jurist": 22757, + "##nity": 22758, + "bard": 22759, + "juventus": 22760, + "groundwater": 22761, + "kern": 22762, + "palaces": 22763, + "helium": 22764, + "boca": 22765, + "cramped": 22766, + "marissa": 22767, + "soto": 22768, + "##worm": 22769, + "jae": 22770, + "princely": 22771, + "##ggy": 22772, + "faso": 22773, + "bazaar": 22774, + "warmly": 22775, + "##voking": 22776, + "229": 22777, + "pairing": 22778, + "##lite": 22779, + "##grate": 22780, + "##nets": 22781, + "wien": 22782, + "freaked": 22783, + "ulysses": 22784, + "rebirth": 22785, + "##alia": 22786, + "##rent": 22787, + "mummy": 22788, + "guzman": 22789, + "jimenez": 22790, + "stilled": 22791, + "##nitz": 22792, + "trajectory": 22793, + "tha": 22794, + "woken": 22795, + "archival": 22796, + "professions": 22797, + "##pts": 22798, + "##pta": 22799, + "hilly": 22800, + "shadowy": 22801, + "shrink": 22802, + "##bolt": 22803, + "norwood": 22804, + "glued": 22805, + "migrate": 22806, + "stereotypes": 22807, + "devoid": 22808, + "##pheus": 22809, + "625": 22810, + "evacuate": 22811, + "horrors": 22812, + "infancy": 22813, + "gotham": 22814, + "knowles": 22815, + "optic": 22816, + "downloaded": 22817, + "sachs": 22818, + "kingsley": 22819, + "parramatta": 22820, + "darryl": 22821, + "mor": 22822, + "##onale": 22823, + "shady": 22824, + "commence": 22825, + "confesses": 22826, + "kan": 22827, + "##meter": 22828, + "##placed": 22829, + "marlborough": 22830, + "roundabout": 22831, + "regents": 22832, + "frigates": 22833, + "io": 22834, + "##imating": 22835, + "gothenburg": 22836, + "revoked": 22837, + "carvings": 22838, + "clockwise": 22839, + "convertible": 22840, + "intruder": 22841, + "##sche": 22842, + "banged": 22843, + "##ogo": 22844, + "vicky": 22845, + "bourgeois": 22846, + "##mony": 22847, + "dupont": 22848, + "footing": 22849, + "##gum": 22850, + "pd": 22851, + "##real": 22852, + "buckle": 22853, + "yun": 22854, + "penthouse": 22855, + "sane": 22856, + "720": 22857, + "serviced": 22858, + "stakeholders": 22859, + "neumann": 22860, + "bb": 22861, + "##eers": 22862, + "comb": 22863, + "##gam": 22864, + "catchment": 22865, + "pinning": 22866, + "rallies": 22867, + "typing": 22868, + "##elles": 22869, + "forefront": 22870, + "freiburg": 22871, + "sweetie": 22872, + "giacomo": 22873, + "widowed": 22874, + "goodwill": 22875, + "worshipped": 22876, + "aspirations": 22877, + "midday": 22878, + "##vat": 22879, + "fishery": 22880, + "##trick": 22881, + "bournemouth": 22882, + "turk": 22883, + "243": 22884, + "hearth": 22885, + "ethanol": 22886, + "guadalajara": 22887, + "murmurs": 22888, + "sl": 22889, + "##uge": 22890, + "afforded": 22891, + "scripted": 22892, + "##hta": 22893, + "wah": 22894, + "##jn": 22895, + "coroner": 22896, + "translucent": 22897, + "252": 22898, + "memorials": 22899, + "puck": 22900, + "progresses": 22901, + "clumsy": 22902, + "##race": 22903, + "315": 22904, + "candace": 22905, + "recounted": 22906, + "##27": 22907, + "##slin": 22908, + "##uve": 22909, + "filtering": 22910, + "##mac": 22911, + "howl": 22912, + "strata": 22913, + "heron": 22914, + "leveled": 22915, + "##ays": 22916, + "dubious": 22917, + "##oja": 22918, + "##т": 22919, + "##wheel": 22920, + "citations": 22921, + "exhibiting": 22922, + "##laya": 22923, + "##mics": 22924, + "##pods": 22925, + "turkic": 22926, + "##lberg": 22927, + "injunction": 22928, + "##ennial": 22929, + "##mit": 22930, + "antibodies": 22931, + "##44": 22932, + "organise": 22933, + "##rigues": 22934, + "cardiovascular": 22935, + "cushion": 22936, + "inverness": 22937, + "##zquez": 22938, + "dia": 22939, + "cocoa": 22940, + "sibling": 22941, + "##tman": 22942, + "##roid": 22943, + "expanse": 22944, + "feasible": 22945, + "tunisian": 22946, + "algiers": 22947, + "##relli": 22948, + "rus": 22949, + "bloomberg": 22950, + "dso": 22951, + "westphalia": 22952, + "bro": 22953, + "tacoma": 22954, + "281": 22955, + "downloads": 22956, + "##ours": 22957, + "konrad": 22958, + "duran": 22959, + "##hdi": 22960, + "continuum": 22961, + "jett": 22962, + "compares": 22963, + "legislator": 22964, + "secession": 22965, + "##nable": 22966, + "##gues": 22967, + "##zuka": 22968, + "translating": 22969, + "reacher": 22970, + "##gley": 22971, + "##ła": 22972, + "aleppo": 22973, + "##agi": 22974, + "tc": 22975, + "orchards": 22976, + "trapping": 22977, + "linguist": 22978, + "versatile": 22979, + "drumming": 22980, + "postage": 22981, + "calhoun": 22982, + "superiors": 22983, + "##mx": 22984, + "barefoot": 22985, + "leary": 22986, + "##cis": 22987, + "ignacio": 22988, + "alfa": 22989, + "kaplan": 22990, + "##rogen": 22991, + "bratislava": 22992, + "mori": 22993, + "##vot": 22994, + "disturb": 22995, + "haas": 22996, + "313": 22997, + "cartridges": 22998, + "gilmore": 22999, + "radiated": 23000, + "salford": 23001, + "tunic": 23002, + "hades": 23003, + "##ulsive": 23004, + "archeological": 23005, + "delilah": 23006, + "magistrates": 23007, + "auditioned": 23008, + "brewster": 23009, + "charters": 23010, + "empowerment": 23011, + "blogs": 23012, + "cappella": 23013, + "dynasties": 23014, + "iroquois": 23015, + "whipping": 23016, + "##krishna": 23017, + "raceway": 23018, + "truths": 23019, + "myra": 23020, + "weaken": 23021, + "judah": 23022, + "mcgregor": 23023, + "##horse": 23024, + "mic": 23025, + "refueling": 23026, + "37th": 23027, + "burnley": 23028, + "bosses": 23029, + "markus": 23030, + "premio": 23031, + "query": 23032, + "##gga": 23033, + "dunbar": 23034, + "##economic": 23035, + "darkest": 23036, + "lyndon": 23037, + "sealing": 23038, + "commendation": 23039, + "reappeared": 23040, + "##mun": 23041, + "addicted": 23042, + "ezio": 23043, + "slaughtered": 23044, + "satisfactory": 23045, + "shuffle": 23046, + "##eves": 23047, + "##thic": 23048, + "##uj": 23049, + "fortification": 23050, + "warrington": 23051, + "##otto": 23052, + "resurrected": 23053, + "fargo": 23054, + "mane": 23055, + "##utable": 23056, + "##lei": 23057, + "##space": 23058, + "foreword": 23059, + "ox": 23060, + "##aris": 23061, + "##vern": 23062, + "abrams": 23063, + "hua": 23064, + "##mento": 23065, + "sakura": 23066, + "##alo": 23067, + "uv": 23068, + "sentimental": 23069, + "##skaya": 23070, + "midfield": 23071, + "##eses": 23072, + "sturdy": 23073, + "scrolls": 23074, + "macleod": 23075, + "##kyu": 23076, + "entropy": 23077, + "##lance": 23078, + "mitochondrial": 23079, + "cicero": 23080, + "excelled": 23081, + "thinner": 23082, + "convoys": 23083, + "perceive": 23084, + "##oslav": 23085, + "##urable": 23086, + "systematically": 23087, + "grind": 23088, + "burkina": 23089, + "287": 23090, + "##tagram": 23091, + "ops": 23092, + "##aman": 23093, + "guantanamo": 23094, + "##cloth": 23095, + "##tite": 23096, + "forcefully": 23097, + "wavy": 23098, + "##jou": 23099, + "pointless": 23100, + "##linger": 23101, + "##tze": 23102, + "layton": 23103, + "portico": 23104, + "superficial": 23105, + "clerical": 23106, + "outlaws": 23107, + "##hism": 23108, + "burials": 23109, + "muir": 23110, + "##inn": 23111, + "creditors": 23112, + "hauling": 23113, + "rattle": 23114, + "##leg": 23115, + "calais": 23116, + "monde": 23117, + "archers": 23118, + "reclaimed": 23119, + "dwell": 23120, + "wexford": 23121, + "hellenic": 23122, + "falsely": 23123, + "remorse": 23124, + "##tek": 23125, + "dough": 23126, + "furnishings": 23127, + "##uttered": 23128, + "gabon": 23129, + "neurological": 23130, + "novice": 23131, + "##igraphy": 23132, + "contemplated": 23133, + "pulpit": 23134, + "nightstand": 23135, + "saratoga": 23136, + "##istan": 23137, + "documenting": 23138, + "pulsing": 23139, + "taluk": 23140, + "##firmed": 23141, + "busted": 23142, + "marital": 23143, + "##rien": 23144, + "disagreements": 23145, + "wasps": 23146, + "##yes": 23147, + "hodge": 23148, + "mcdonnell": 23149, + "mimic": 23150, + "fran": 23151, + "pendant": 23152, + "dhabi": 23153, + "musa": 23154, + "##nington": 23155, + "congratulations": 23156, + "argent": 23157, + "darrell": 23158, + "concussion": 23159, + "losers": 23160, + "regrets": 23161, + "thessaloniki": 23162, + "reversal": 23163, + "donaldson": 23164, + "hardwood": 23165, + "thence": 23166, + "achilles": 23167, + "ritter": 23168, + "##eran": 23169, + "demonic": 23170, + "jurgen": 23171, + "prophets": 23172, + "goethe": 23173, + "eki": 23174, + "classmate": 23175, + "buff": 23176, + "##cking": 23177, + "yank": 23178, + "irrational": 23179, + "##inging": 23180, + "perished": 23181, + "seductive": 23182, + "qur": 23183, + "sourced": 23184, + "##crat": 23185, + "##typic": 23186, + "mustard": 23187, + "ravine": 23188, + "barre": 23189, + "horizontally": 23190, + "characterization": 23191, + "phylogenetic": 23192, + "boise": 23193, + "##dit": 23194, + "##runner": 23195, + "##tower": 23196, + "brutally": 23197, + "intercourse": 23198, + "seduce": 23199, + "##bbing": 23200, + "fay": 23201, + "ferris": 23202, + "ogden": 23203, + "amar": 23204, + "nik": 23205, + "unarmed": 23206, + "##inator": 23207, + "evaluating": 23208, + "kyrgyzstan": 23209, + "sweetness": 23210, + "##lford": 23211, + "##oki": 23212, + "mccormick": 23213, + "meiji": 23214, + "notoriety": 23215, + "stimulate": 23216, + "disrupt": 23217, + "figuring": 23218, + "instructional": 23219, + "mcgrath": 23220, + "##zoo": 23221, + "groundbreaking": 23222, + "##lto": 23223, + "flinch": 23224, + "khorasan": 23225, + "agrarian": 23226, + "bengals": 23227, + "mixer": 23228, + "radiating": 23229, + "##sov": 23230, + "ingram": 23231, + "pitchers": 23232, + "nad": 23233, + "tariff": 23234, + "##cript": 23235, + "tata": 23236, + "##codes": 23237, + "##emi": 23238, + "##ungen": 23239, + "appellate": 23240, + "lehigh": 23241, + "##bled": 23242, + "##giri": 23243, + "brawl": 23244, + "duct": 23245, + "texans": 23246, + "##ciation": 23247, + "##ropolis": 23248, + "skipper": 23249, + "speculative": 23250, + "vomit": 23251, + "doctrines": 23252, + "stresses": 23253, + "253": 23254, + "davy": 23255, + "graders": 23256, + "whitehead": 23257, + "jozef": 23258, + "timely": 23259, + "cumulative": 23260, + "haryana": 23261, + "paints": 23262, + "appropriately": 23263, + "boon": 23264, + "cactus": 23265, + "##ales": 23266, + "##pid": 23267, + "dow": 23268, + "legions": 23269, + "##pit": 23270, + "perceptions": 23271, + "1730": 23272, + "picturesque": 23273, + "##yse": 23274, + "periphery": 23275, + "rune": 23276, + "wr": 23277, + "##aha": 23278, + "celtics": 23279, + "sentencing": 23280, + "whoa": 23281, + "##erin": 23282, + "confirms": 23283, + "variance": 23284, + "425": 23285, + "moines": 23286, + "mathews": 23287, + "spade": 23288, + "rave": 23289, + "m1": 23290, + "fronted": 23291, + "fx": 23292, + "blending": 23293, + "alleging": 23294, + "reared": 23295, + "##gl": 23296, + "237": 23297, + "##paper": 23298, + "grassroots": 23299, + "eroded": 23300, + "##free": 23301, + "##physical": 23302, + "directs": 23303, + "ordeal": 23304, + "##sław": 23305, + "accelerate": 23306, + "hacker": 23307, + "rooftop": 23308, + "##inia": 23309, + "lev": 23310, + "buys": 23311, + "cebu": 23312, + "devote": 23313, + "##lce": 23314, + "specialising": 23315, + "##ulsion": 23316, + "choreographed": 23317, + "repetition": 23318, + "warehouses": 23319, + "##ryl": 23320, + "paisley": 23321, + "tuscany": 23322, + "analogy": 23323, + "sorcerer": 23324, + "hash": 23325, + "huts": 23326, + "shards": 23327, + "descends": 23328, + "exclude": 23329, + "nix": 23330, + "chaplin": 23331, + "gaga": 23332, + "ito": 23333, + "vane": 23334, + "##drich": 23335, + "causeway": 23336, + "misconduct": 23337, + "limo": 23338, + "orchestrated": 23339, + "glands": 23340, + "jana": 23341, + "##kot": 23342, + "u2": 23343, + "##mple": 23344, + "##sons": 23345, + "branching": 23346, + "contrasts": 23347, + "scoop": 23348, + "longed": 23349, + "##virus": 23350, + "chattanooga": 23351, + "##75": 23352, + "syrup": 23353, + "cornerstone": 23354, + "##tized": 23355, + "##mind": 23356, + "##iaceae": 23357, + "careless": 23358, + "precedence": 23359, + "frescoes": 23360, + "##uet": 23361, + "chilled": 23362, + "consult": 23363, + "modelled": 23364, + "snatch": 23365, + "peat": 23366, + "##thermal": 23367, + "caucasian": 23368, + "humane": 23369, + "relaxation": 23370, + "spins": 23371, + "temperance": 23372, + "##lbert": 23373, + "occupations": 23374, + "lambda": 23375, + "hybrids": 23376, + "moons": 23377, + "mp3": 23378, + "##oese": 23379, + "247": 23380, + "rolf": 23381, + "societal": 23382, + "yerevan": 23383, + "ness": 23384, + "##ssler": 23385, + "befriended": 23386, + "mechanized": 23387, + "nominate": 23388, + "trough": 23389, + "boasted": 23390, + "cues": 23391, + "seater": 23392, + "##hom": 23393, + "bends": 23394, + "##tangle": 23395, + "conductors": 23396, + "emptiness": 23397, + "##lmer": 23398, + "eurasian": 23399, + "adriatic": 23400, + "tian": 23401, + "##cie": 23402, + "anxiously": 23403, + "lark": 23404, + "propellers": 23405, + "chichester": 23406, + "jock": 23407, + "ev": 23408, + "2a": 23409, + "##holding": 23410, + "credible": 23411, + "recounts": 23412, + "tori": 23413, + "loyalist": 23414, + "abduction": 23415, + "##hoot": 23416, + "##redo": 23417, + "nepali": 23418, + "##mite": 23419, + "ventral": 23420, + "tempting": 23421, + "##ango": 23422, + "##crats": 23423, + "steered": 23424, + "##wice": 23425, + "javelin": 23426, + "dipping": 23427, + "laborers": 23428, + "prentice": 23429, + "looming": 23430, + "titanium": 23431, + "##ː": 23432, + "badges": 23433, + "emir": 23434, + "tensor": 23435, + "##ntation": 23436, + "egyptians": 23437, + "rash": 23438, + "denies": 23439, + "hawthorne": 23440, + "lombard": 23441, + "showers": 23442, + "wehrmacht": 23443, + "dietary": 23444, + "trojan": 23445, + "##reus": 23446, + "welles": 23447, + "executing": 23448, + "horseshoe": 23449, + "lifeboat": 23450, + "##lak": 23451, + "elsa": 23452, + "infirmary": 23453, + "nearing": 23454, + "roberta": 23455, + "boyer": 23456, + "mutter": 23457, + "trillion": 23458, + "joanne": 23459, + "##fine": 23460, + "##oked": 23461, + "sinks": 23462, + "vortex": 23463, + "uruguayan": 23464, + "clasp": 23465, + "sirius": 23466, + "##block": 23467, + "accelerator": 23468, + "prohibit": 23469, + "sunken": 23470, + "byu": 23471, + "chronological": 23472, + "diplomats": 23473, + "ochreous": 23474, + "510": 23475, + "symmetrical": 23476, + "1644": 23477, + "maia": 23478, + "##tology": 23479, + "salts": 23480, + "reigns": 23481, + "atrocities": 23482, + "##ия": 23483, + "hess": 23484, + "bared": 23485, + "issn": 23486, + "##vyn": 23487, + "cater": 23488, + "saturated": 23489, + "##cycle": 23490, + "##isse": 23491, + "sable": 23492, + "voyager": 23493, + "dyer": 23494, + "yusuf": 23495, + "##inge": 23496, + "fountains": 23497, + "wolff": 23498, + "##39": 23499, + "##nni": 23500, + "engraving": 23501, + "rollins": 23502, + "atheist": 23503, + "ominous": 23504, + "##ault": 23505, + "herr": 23506, + "chariot": 23507, + "martina": 23508, + "strung": 23509, + "##fell": 23510, + "##farlane": 23511, + "horrific": 23512, + "sahib": 23513, + "gazes": 23514, + "saetan": 23515, + "erased": 23516, + "ptolemy": 23517, + "##olic": 23518, + "flushing": 23519, + "lauderdale": 23520, + "analytic": 23521, + "##ices": 23522, + "530": 23523, + "navarro": 23524, + "beak": 23525, + "gorilla": 23526, + "herrera": 23527, + "broom": 23528, + "guadalupe": 23529, + "raiding": 23530, + "sykes": 23531, + "311": 23532, + "bsc": 23533, + "deliveries": 23534, + "1720": 23535, + "invasions": 23536, + "carmichael": 23537, + "tajikistan": 23538, + "thematic": 23539, + "ecumenical": 23540, + "sentiments": 23541, + "onstage": 23542, + "##rians": 23543, + "##brand": 23544, + "##sume": 23545, + "catastrophic": 23546, + "flanks": 23547, + "molten": 23548, + "##arns": 23549, + "waller": 23550, + "aimee": 23551, + "terminating": 23552, + "##icing": 23553, + "alternately": 23554, + "##oche": 23555, + "nehru": 23556, + "printers": 23557, + "outraged": 23558, + "##eving": 23559, + "empires": 23560, + "template": 23561, + "banners": 23562, + "repetitive": 23563, + "za": 23564, + "##oise": 23565, + "vegetarian": 23566, + "##tell": 23567, + "guiana": 23568, + "opt": 23569, + "cavendish": 23570, + "lucknow": 23571, + "synthesized": 23572, + "##hani": 23573, + "##mada": 23574, + "finalized": 23575, + "##ctable": 23576, + "fictitious": 23577, + "mayoral": 23578, + "unreliable": 23579, + "##enham": 23580, + "embracing": 23581, + "peppers": 23582, + "rbis": 23583, + "##chio": 23584, + "##neo": 23585, + "inhibition": 23586, + "slashed": 23587, + "togo": 23588, + "orderly": 23589, + "embroidered": 23590, + "safari": 23591, + "salty": 23592, + "236": 23593, + "barron": 23594, + "benito": 23595, + "totaled": 23596, + "##dak": 23597, + "pubs": 23598, + "simulated": 23599, + "caden": 23600, + "devin": 23601, + "tolkien": 23602, + "momma": 23603, + "welding": 23604, + "sesame": 23605, + "##ept": 23606, + "gottingen": 23607, + "hardness": 23608, + "630": 23609, + "shaman": 23610, + "temeraire": 23611, + "620": 23612, + "adequately": 23613, + "pediatric": 23614, + "##kit": 23615, + "ck": 23616, + "assertion": 23617, + "radicals": 23618, + "composure": 23619, + "cadence": 23620, + "seafood": 23621, + "beaufort": 23622, + "lazarus": 23623, + "mani": 23624, + "warily": 23625, + "cunning": 23626, + "kurdistan": 23627, + "249": 23628, + "cantata": 23629, + "##kir": 23630, + "ares": 23631, + "##41": 23632, + "##clusive": 23633, + "nape": 23634, + "townland": 23635, + "geared": 23636, + "insulted": 23637, + "flutter": 23638, + "boating": 23639, + "violate": 23640, + "draper": 23641, + "dumping": 23642, + "malmo": 23643, + "##hh": 23644, + "##romatic": 23645, + "firearm": 23646, + "alta": 23647, + "bono": 23648, + "obscured": 23649, + "##clave": 23650, + "exceeds": 23651, + "panorama": 23652, + "unbelievable": 23653, + "##train": 23654, + "preschool": 23655, + "##essed": 23656, + "disconnected": 23657, + "installing": 23658, + "rescuing": 23659, + "secretaries": 23660, + "accessibility": 23661, + "##castle": 23662, + "##drive": 23663, + "##ifice": 23664, + "##film": 23665, + "bouts": 23666, + "slug": 23667, + "waterway": 23668, + "mindanao": 23669, + "##buro": 23670, + "##ratic": 23671, + "halves": 23672, + "##ل": 23673, + "calming": 23674, + "liter": 23675, + "maternity": 23676, + "adorable": 23677, + "bragg": 23678, + "electrification": 23679, + "mcc": 23680, + "##dote": 23681, + "roxy": 23682, + "schizophrenia": 23683, + "##body": 23684, + "munoz": 23685, + "kaye": 23686, + "whaling": 23687, + "239": 23688, + "mil": 23689, + "tingling": 23690, + "tolerant": 23691, + "##ago": 23692, + "unconventional": 23693, + "volcanoes": 23694, + "##finder": 23695, + "deportivo": 23696, + "##llie": 23697, + "robson": 23698, + "kaufman": 23699, + "neuroscience": 23700, + "wai": 23701, + "deportation": 23702, + "masovian": 23703, + "scraping": 23704, + "converse": 23705, + "##bh": 23706, + "hacking": 23707, + "bulge": 23708, + "##oun": 23709, + "administratively": 23710, + "yao": 23711, + "580": 23712, + "amp": 23713, + "mammoth": 23714, + "booster": 23715, + "claremont": 23716, + "hooper": 23717, + "nomenclature": 23718, + "pursuits": 23719, + "mclaughlin": 23720, + "melinda": 23721, + "##sul": 23722, + "catfish": 23723, + "barclay": 23724, + "substrates": 23725, + "taxa": 23726, + "zee": 23727, + "originals": 23728, + "kimberly": 23729, + "packets": 23730, + "padma": 23731, + "##ality": 23732, + "borrowing": 23733, + "ostensibly": 23734, + "solvent": 23735, + "##bri": 23736, + "##genesis": 23737, + "##mist": 23738, + "lukas": 23739, + "shreveport": 23740, + "veracruz": 23741, + "##ь": 23742, + "##lou": 23743, + "##wives": 23744, + "cheney": 23745, + "tt": 23746, + "anatolia": 23747, + "hobbs": 23748, + "##zyn": 23749, + "cyclic": 23750, + "radiant": 23751, + "alistair": 23752, + "greenish": 23753, + "siena": 23754, + "dat": 23755, + "independents": 23756, + "##bation": 23757, + "conform": 23758, + "pieter": 23759, + "hyper": 23760, + "applicant": 23761, + "bradshaw": 23762, + "spores": 23763, + "telangana": 23764, + "vinci": 23765, + "inexpensive": 23766, + "nuclei": 23767, + "322": 23768, + "jang": 23769, + "nme": 23770, + "soho": 23771, + "spd": 23772, + "##ign": 23773, + "cradled": 23774, + "receptionist": 23775, + "pow": 23776, + "##43": 23777, + "##rika": 23778, + "fascism": 23779, + "##ifer": 23780, + "experimenting": 23781, + "##ading": 23782, + "##iec": 23783, + "##region": 23784, + "345": 23785, + "jocelyn": 23786, + "maris": 23787, + "stair": 23788, + "nocturnal": 23789, + "toro": 23790, + "constabulary": 23791, + "elgin": 23792, + "##kker": 23793, + "msc": 23794, + "##giving": 23795, + "##schen": 23796, + "##rase": 23797, + "doherty": 23798, + "doping": 23799, + "sarcastically": 23800, + "batter": 23801, + "maneuvers": 23802, + "##cano": 23803, + "##apple": 23804, + "##gai": 23805, + "##git": 23806, + "intrinsic": 23807, + "##nst": 23808, + "##stor": 23809, + "1753": 23810, + "showtime": 23811, + "cafes": 23812, + "gasps": 23813, + "lviv": 23814, + "ushered": 23815, + "##thed": 23816, + "fours": 23817, + "restart": 23818, + "astonishment": 23819, + "transmitting": 23820, + "flyer": 23821, + "shrugs": 23822, + "##sau": 23823, + "intriguing": 23824, + "cones": 23825, + "dictated": 23826, + "mushrooms": 23827, + "medial": 23828, + "##kovsky": 23829, + "##elman": 23830, + "escorting": 23831, + "gaped": 23832, + "##26": 23833, + "godfather": 23834, + "##door": 23835, + "##sell": 23836, + "djs": 23837, + "recaptured": 23838, + "timetable": 23839, + "vila": 23840, + "1710": 23841, + "3a": 23842, + "aerodrome": 23843, + "mortals": 23844, + "scientology": 23845, + "##orne": 23846, + "angelina": 23847, + "mag": 23848, + "convection": 23849, + "unpaid": 23850, + "insertion": 23851, + "intermittent": 23852, + "lego": 23853, + "##nated": 23854, + "endeavor": 23855, + "kota": 23856, + "pereira": 23857, + "##lz": 23858, + "304": 23859, + "bwv": 23860, + "glamorgan": 23861, + "insults": 23862, + "agatha": 23863, + "fey": 23864, + "##cend": 23865, + "fleetwood": 23866, + "mahogany": 23867, + "protruding": 23868, + "steamship": 23869, + "zeta": 23870, + "##arty": 23871, + "mcguire": 23872, + "suspense": 23873, + "##sphere": 23874, + "advising": 23875, + "urges": 23876, + "##wala": 23877, + "hurriedly": 23878, + "meteor": 23879, + "gilded": 23880, + "inline": 23881, + "arroyo": 23882, + "stalker": 23883, + "##oge": 23884, + "excitedly": 23885, + "revered": 23886, + "##cure": 23887, + "earle": 23888, + "introductory": 23889, + "##break": 23890, + "##ilde": 23891, + "mutants": 23892, + "puff": 23893, + "pulses": 23894, + "reinforcement": 23895, + "##haling": 23896, + "curses": 23897, + "lizards": 23898, + "stalk": 23899, + "correlated": 23900, + "##fixed": 23901, + "fallout": 23902, + "macquarie": 23903, + "##unas": 23904, + "bearded": 23905, + "denton": 23906, + "heaving": 23907, + "802": 23908, + "##ocation": 23909, + "winery": 23910, + "assign": 23911, + "dortmund": 23912, + "##lkirk": 23913, + "everest": 23914, + "invariant": 23915, + "charismatic": 23916, + "susie": 23917, + "##elling": 23918, + "bled": 23919, + "lesley": 23920, + "telegram": 23921, + "sumner": 23922, + "bk": 23923, + "##ogen": 23924, + "##к": 23925, + "wilcox": 23926, + "needy": 23927, + "colbert": 23928, + "duval": 23929, + "##iferous": 23930, + "##mbled": 23931, + "allotted": 23932, + "attends": 23933, + "imperative": 23934, + "##hita": 23935, + "replacements": 23936, + "hawker": 23937, + "##inda": 23938, + "insurgency": 23939, + "##zee": 23940, + "##eke": 23941, + "casts": 23942, + "##yla": 23943, + "680": 23944, + "ives": 23945, + "transitioned": 23946, + "##pack": 23947, + "##powering": 23948, + "authoritative": 23949, + "baylor": 23950, + "flex": 23951, + "cringed": 23952, + "plaintiffs": 23953, + "woodrow": 23954, + "##skie": 23955, + "drastic": 23956, + "ape": 23957, + "aroma": 23958, + "unfolded": 23959, + "commotion": 23960, + "nt": 23961, + "preoccupied": 23962, + "theta": 23963, + "routines": 23964, + "lasers": 23965, + "privatization": 23966, + "wand": 23967, + "domino": 23968, + "ek": 23969, + "clenching": 23970, + "nsa": 23971, + "strategically": 23972, + "showered": 23973, + "bile": 23974, + "handkerchief": 23975, + "pere": 23976, + "storing": 23977, + "christophe": 23978, + "insulting": 23979, + "316": 23980, + "nakamura": 23981, + "romani": 23982, + "asiatic": 23983, + "magdalena": 23984, + "palma": 23985, + "cruises": 23986, + "stripping": 23987, + "405": 23988, + "konstantin": 23989, + "soaring": 23990, + "##berman": 23991, + "colloquially": 23992, + "forerunner": 23993, + "havilland": 23994, + "incarcerated": 23995, + "parasites": 23996, + "sincerity": 23997, + "##utus": 23998, + "disks": 23999, + "plank": 24000, + "saigon": 24001, + "##ining": 24002, + "corbin": 24003, + "homo": 24004, + "ornaments": 24005, + "powerhouse": 24006, + "##tlement": 24007, + "chong": 24008, + "fastened": 24009, + "feasibility": 24010, + "idf": 24011, + "morphological": 24012, + "usable": 24013, + "##nish": 24014, + "##zuki": 24015, + "aqueduct": 24016, + "jaguars": 24017, + "keepers": 24018, + "##flies": 24019, + "aleksandr": 24020, + "faust": 24021, + "assigns": 24022, + "ewing": 24023, + "bacterium": 24024, + "hurled": 24025, + "tricky": 24026, + "hungarians": 24027, + "integers": 24028, + "wallis": 24029, + "321": 24030, + "yamaha": 24031, + "##isha": 24032, + "hushed": 24033, + "oblivion": 24034, + "aviator": 24035, + "evangelist": 24036, + "friars": 24037, + "##eller": 24038, + "monograph": 24039, + "ode": 24040, + "##nary": 24041, + "airplanes": 24042, + "labourers": 24043, + "charms": 24044, + "##nee": 24045, + "1661": 24046, + "hagen": 24047, + "tnt": 24048, + "rudder": 24049, + "fiesta": 24050, + "transcript": 24051, + "dorothea": 24052, + "ska": 24053, + "inhibitor": 24054, + "maccabi": 24055, + "retorted": 24056, + "raining": 24057, + "encompassed": 24058, + "clauses": 24059, + "menacing": 24060, + "1642": 24061, + "lineman": 24062, + "##gist": 24063, + "vamps": 24064, + "##ape": 24065, + "##dick": 24066, + "gloom": 24067, + "##rera": 24068, + "dealings": 24069, + "easing": 24070, + "seekers": 24071, + "##nut": 24072, + "##pment": 24073, + "helens": 24074, + "unmanned": 24075, + "##anu": 24076, + "##isson": 24077, + "basics": 24078, + "##amy": 24079, + "##ckman": 24080, + "adjustments": 24081, + "1688": 24082, + "brutality": 24083, + "horne": 24084, + "##zell": 24085, + "sui": 24086, + "##55": 24087, + "##mable": 24088, + "aggregator": 24089, + "##thal": 24090, + "rhino": 24091, + "##drick": 24092, + "##vira": 24093, + "counters": 24094, + "zoom": 24095, + "##01": 24096, + "##rting": 24097, + "mn": 24098, + "montenegrin": 24099, + "packard": 24100, + "##unciation": 24101, + "##♭": 24102, + "##kki": 24103, + "reclaim": 24104, + "scholastic": 24105, + "thugs": 24106, + "pulsed": 24107, + "##icia": 24108, + "syriac": 24109, + "quan": 24110, + "saddam": 24111, + "banda": 24112, + "kobe": 24113, + "blaming": 24114, + "buddies": 24115, + "dissent": 24116, + "##lusion": 24117, + "##usia": 24118, + "corbett": 24119, + "jaya": 24120, + "delle": 24121, + "erratic": 24122, + "lexie": 24123, + "##hesis": 24124, + "435": 24125, + "amiga": 24126, + "hermes": 24127, + "##pressing": 24128, + "##leen": 24129, + "chapels": 24130, + "gospels": 24131, + "jamal": 24132, + "##uating": 24133, + "compute": 24134, + "revolving": 24135, + "warp": 24136, + "##sso": 24137, + "##thes": 24138, + "armory": 24139, + "##eras": 24140, + "##gol": 24141, + "antrim": 24142, + "loki": 24143, + "##kow": 24144, + "##asian": 24145, + "##good": 24146, + "##zano": 24147, + "braid": 24148, + "handwriting": 24149, + "subdistrict": 24150, + "funky": 24151, + "pantheon": 24152, + "##iculate": 24153, + "concurrency": 24154, + "estimation": 24155, + "improper": 24156, + "juliana": 24157, + "##his": 24158, + "newcomers": 24159, + "johnstone": 24160, + "staten": 24161, + "communicated": 24162, + "##oco": 24163, + "##alle": 24164, + "sausage": 24165, + "stormy": 24166, + "##stered": 24167, + "##tters": 24168, + "superfamily": 24169, + "##grade": 24170, + "acidic": 24171, + "collateral": 24172, + "tabloid": 24173, + "##oped": 24174, + "##rza": 24175, + "bladder": 24176, + "austen": 24177, + "##ellant": 24178, + "mcgraw": 24179, + "##hay": 24180, + "hannibal": 24181, + "mein": 24182, + "aquino": 24183, + "lucifer": 24184, + "wo": 24185, + "badger": 24186, + "boar": 24187, + "cher": 24188, + "christensen": 24189, + "greenberg": 24190, + "interruption": 24191, + "##kken": 24192, + "jem": 24193, + "244": 24194, + "mocked": 24195, + "bottoms": 24196, + "cambridgeshire": 24197, + "##lide": 24198, + "sprawling": 24199, + "##bbly": 24200, + "eastwood": 24201, + "ghent": 24202, + "synth": 24203, + "##buck": 24204, + "advisers": 24205, + "##bah": 24206, + "nominally": 24207, + "hapoel": 24208, + "qu": 24209, + "daggers": 24210, + "estranged": 24211, + "fabricated": 24212, + "towels": 24213, + "vinnie": 24214, + "wcw": 24215, + "misunderstanding": 24216, + "anglia": 24217, + "nothin": 24218, + "unmistakable": 24219, + "##dust": 24220, + "##lova": 24221, + "chilly": 24222, + "marquette": 24223, + "truss": 24224, + "##edge": 24225, + "##erine": 24226, + "reece": 24227, + "##lty": 24228, + "##chemist": 24229, + "##connected": 24230, + "272": 24231, + "308": 24232, + "41st": 24233, + "bash": 24234, + "raion": 24235, + "waterfalls": 24236, + "##ump": 24237, + "##main": 24238, + "labyrinth": 24239, + "queue": 24240, + "theorist": 24241, + "##istle": 24242, + "bharatiya": 24243, + "flexed": 24244, + "soundtracks": 24245, + "rooney": 24246, + "leftist": 24247, + "patrolling": 24248, + "wharton": 24249, + "plainly": 24250, + "alleviate": 24251, + "eastman": 24252, + "schuster": 24253, + "topographic": 24254, + "engages": 24255, + "immensely": 24256, + "unbearable": 24257, + "fairchild": 24258, + "1620": 24259, + "dona": 24260, + "lurking": 24261, + "parisian": 24262, + "oliveira": 24263, + "ia": 24264, + "indictment": 24265, + "hahn": 24266, + "bangladeshi": 24267, + "##aster": 24268, + "vivo": 24269, + "##uming": 24270, + "##ential": 24271, + "antonia": 24272, + "expects": 24273, + "indoors": 24274, + "kildare": 24275, + "harlan": 24276, + "##logue": 24277, + "##ogenic": 24278, + "##sities": 24279, + "forgiven": 24280, + "##wat": 24281, + "childish": 24282, + "tavi": 24283, + "##mide": 24284, + "##orra": 24285, + "plausible": 24286, + "grimm": 24287, + "successively": 24288, + "scooted": 24289, + "##bola": 24290, + "##dget": 24291, + "##rith": 24292, + "spartans": 24293, + "emery": 24294, + "flatly": 24295, + "azure": 24296, + "epilogue": 24297, + "##wark": 24298, + "flourish": 24299, + "##iny": 24300, + "##tracted": 24301, + "##overs": 24302, + "##oshi": 24303, + "bestseller": 24304, + "distressed": 24305, + "receipt": 24306, + "spitting": 24307, + "hermit": 24308, + "topological": 24309, + "##cot": 24310, + "drilled": 24311, + "subunit": 24312, + "francs": 24313, + "##layer": 24314, + "eel": 24315, + "##fk": 24316, + "##itas": 24317, + "octopus": 24318, + "footprint": 24319, + "petitions": 24320, + "ufo": 24321, + "##say": 24322, + "##foil": 24323, + "interfering": 24324, + "leaking": 24325, + "palo": 24326, + "##metry": 24327, + "thistle": 24328, + "valiant": 24329, + "##pic": 24330, + "narayan": 24331, + "mcpherson": 24332, + "##fast": 24333, + "gonzales": 24334, + "##ym": 24335, + "##enne": 24336, + "dustin": 24337, + "novgorod": 24338, + "solos": 24339, + "##zman": 24340, + "doin": 24341, + "##raph": 24342, + "##patient": 24343, + "##meyer": 24344, + "soluble": 24345, + "ashland": 24346, + "cuffs": 24347, + "carole": 24348, + "pendleton": 24349, + "whistling": 24350, + "vassal": 24351, + "##river": 24352, + "deviation": 24353, + "revisited": 24354, + "constituents": 24355, + "rallied": 24356, + "rotate": 24357, + "loomed": 24358, + "##eil": 24359, + "##nting": 24360, + "amateurs": 24361, + "augsburg": 24362, + "auschwitz": 24363, + "crowns": 24364, + "skeletons": 24365, + "##cona": 24366, + "bonnet": 24367, + "257": 24368, + "dummy": 24369, + "globalization": 24370, + "simeon": 24371, + "sleeper": 24372, + "mandal": 24373, + "differentiated": 24374, + "##crow": 24375, + "##mare": 24376, + "milne": 24377, + "bundled": 24378, + "exasperated": 24379, + "talmud": 24380, + "owes": 24381, + "segregated": 24382, + "##feng": 24383, + "##uary": 24384, + "dentist": 24385, + "piracy": 24386, + "props": 24387, + "##rang": 24388, + "devlin": 24389, + "##torium": 24390, + "malicious": 24391, + "paws": 24392, + "##laid": 24393, + "dependency": 24394, + "##ergy": 24395, + "##fers": 24396, + "##enna": 24397, + "258": 24398, + "pistons": 24399, + "rourke": 24400, + "jed": 24401, + "grammatical": 24402, + "tres": 24403, + "maha": 24404, + "wig": 24405, + "512": 24406, + "ghostly": 24407, + "jayne": 24408, + "##achal": 24409, + "##creen": 24410, + "##ilis": 24411, + "##lins": 24412, + "##rence": 24413, + "designate": 24414, + "##with": 24415, + "arrogance": 24416, + "cambodian": 24417, + "clones": 24418, + "showdown": 24419, + "throttle": 24420, + "twain": 24421, + "##ception": 24422, + "lobes": 24423, + "metz": 24424, + "nagoya": 24425, + "335": 24426, + "braking": 24427, + "##furt": 24428, + "385": 24429, + "roaming": 24430, + "##minster": 24431, + "amin": 24432, + "crippled": 24433, + "##37": 24434, + "##llary": 24435, + "indifferent": 24436, + "hoffmann": 24437, + "idols": 24438, + "intimidating": 24439, + "1751": 24440, + "261": 24441, + "influenza": 24442, + "memo": 24443, + "onions": 24444, + "1748": 24445, + "bandage": 24446, + "consciously": 24447, + "##landa": 24448, + "##rage": 24449, + "clandestine": 24450, + "observes": 24451, + "swiped": 24452, + "tangle": 24453, + "##ener": 24454, + "##jected": 24455, + "##trum": 24456, + "##bill": 24457, + "##lta": 24458, + "hugs": 24459, + "congresses": 24460, + "josiah": 24461, + "spirited": 24462, + "##dek": 24463, + "humanist": 24464, + "managerial": 24465, + "filmmaking": 24466, + "inmate": 24467, + "rhymes": 24468, + "debuting": 24469, + "grimsby": 24470, + "ur": 24471, + "##laze": 24472, + "duplicate": 24473, + "vigor": 24474, + "##tf": 24475, + "republished": 24476, + "bolshevik": 24477, + "refurbishment": 24478, + "antibiotics": 24479, + "martini": 24480, + "methane": 24481, + "newscasts": 24482, + "royale": 24483, + "horizons": 24484, + "levant": 24485, + "iain": 24486, + "visas": 24487, + "##ischen": 24488, + "paler": 24489, + "##around": 24490, + "manifestation": 24491, + "snuck": 24492, + "alf": 24493, + "chop": 24494, + "futile": 24495, + "pedestal": 24496, + "rehab": 24497, + "##kat": 24498, + "bmg": 24499, + "kerman": 24500, + "res": 24501, + "fairbanks": 24502, + "jarrett": 24503, + "abstraction": 24504, + "saharan": 24505, + "##zek": 24506, + "1746": 24507, + "procedural": 24508, + "clearer": 24509, + "kincaid": 24510, + "sash": 24511, + "luciano": 24512, + "##ffey": 24513, + "crunch": 24514, + "helmut": 24515, + "##vara": 24516, + "revolutionaries": 24517, + "##tute": 24518, + "creamy": 24519, + "leach": 24520, + "##mmon": 24521, + "1747": 24522, + "permitting": 24523, + "nes": 24524, + "plight": 24525, + "wendell": 24526, + "##lese": 24527, + "contra": 24528, + "ts": 24529, + "clancy": 24530, + "ipa": 24531, + "mach": 24532, + "staples": 24533, + "autopsy": 24534, + "disturbances": 24535, + "nueva": 24536, + "karin": 24537, + "pontiac": 24538, + "##uding": 24539, + "proxy": 24540, + "venerable": 24541, + "haunt": 24542, + "leto": 24543, + "bergman": 24544, + "expands": 24545, + "##helm": 24546, + "wal": 24547, + "##pipe": 24548, + "canning": 24549, + "celine": 24550, + "cords": 24551, + "obesity": 24552, + "##enary": 24553, + "intrusion": 24554, + "planner": 24555, + "##phate": 24556, + "reasoned": 24557, + "sequencing": 24558, + "307": 24559, + "harrow": 24560, + "##chon": 24561, + "##dora": 24562, + "marred": 24563, + "mcintyre": 24564, + "repay": 24565, + "tarzan": 24566, + "darting": 24567, + "248": 24568, + "harrisburg": 24569, + "margarita": 24570, + "repulsed": 24571, + "##hur": 24572, + "##lding": 24573, + "belinda": 24574, + "hamburger": 24575, + "novo": 24576, + "compliant": 24577, + "runways": 24578, + "bingham": 24579, + "registrar": 24580, + "skyscraper": 24581, + "ic": 24582, + "cuthbert": 24583, + "improvisation": 24584, + "livelihood": 24585, + "##corp": 24586, + "##elial": 24587, + "admiring": 24588, + "##dened": 24589, + "sporadic": 24590, + "believer": 24591, + "casablanca": 24592, + "popcorn": 24593, + "##29": 24594, + "asha": 24595, + "shovel": 24596, + "##bek": 24597, + "##dice": 24598, + "coiled": 24599, + "tangible": 24600, + "##dez": 24601, + "casper": 24602, + "elsie": 24603, + "resin": 24604, + "tenderness": 24605, + "rectory": 24606, + "##ivision": 24607, + "avail": 24608, + "sonar": 24609, + "##mori": 24610, + "boutique": 24611, + "##dier": 24612, + "guerre": 24613, + "bathed": 24614, + "upbringing": 24615, + "vaulted": 24616, + "sandals": 24617, + "blessings": 24618, + "##naut": 24619, + "##utnant": 24620, + "1680": 24621, + "306": 24622, + "foxes": 24623, + "pia": 24624, + "corrosion": 24625, + "hesitantly": 24626, + "confederates": 24627, + "crystalline": 24628, + "footprints": 24629, + "shapiro": 24630, + "tirana": 24631, + "valentin": 24632, + "drones": 24633, + "45th": 24634, + "microscope": 24635, + "shipments": 24636, + "texted": 24637, + "inquisition": 24638, + "wry": 24639, + "guernsey": 24640, + "unauthorized": 24641, + "resigning": 24642, + "760": 24643, + "ripple": 24644, + "schubert": 24645, + "stu": 24646, + "reassure": 24647, + "felony": 24648, + "##ardo": 24649, + "brittle": 24650, + "koreans": 24651, + "##havan": 24652, + "##ives": 24653, + "dun": 24654, + "implicit": 24655, + "tyres": 24656, + "##aldi": 24657, + "##lth": 24658, + "magnolia": 24659, + "##ehan": 24660, + "##puri": 24661, + "##poulos": 24662, + "aggressively": 24663, + "fei": 24664, + "gr": 24665, + "familiarity": 24666, + "##poo": 24667, + "indicative": 24668, + "##trust": 24669, + "fundamentally": 24670, + "jimmie": 24671, + "overrun": 24672, + "395": 24673, + "anchors": 24674, + "moans": 24675, + "##opus": 24676, + "britannia": 24677, + "armagh": 24678, + "##ggle": 24679, + "purposely": 24680, + "seizing": 24681, + "##vao": 24682, + "bewildered": 24683, + "mundane": 24684, + "avoidance": 24685, + "cosmopolitan": 24686, + "geometridae": 24687, + "quartermaster": 24688, + "caf": 24689, + "415": 24690, + "chatter": 24691, + "engulfed": 24692, + "gleam": 24693, + "purge": 24694, + "##icate": 24695, + "juliette": 24696, + "jurisprudence": 24697, + "guerra": 24698, + "revisions": 24699, + "##bn": 24700, + "casimir": 24701, + "brew": 24702, + "##jm": 24703, + "1749": 24704, + "clapton": 24705, + "cloudy": 24706, + "conde": 24707, + "hermitage": 24708, + "278": 24709, + "simulations": 24710, + "torches": 24711, + "vincenzo": 24712, + "matteo": 24713, + "##rill": 24714, + "hidalgo": 24715, + "booming": 24716, + "westbound": 24717, + "accomplishment": 24718, + "tentacles": 24719, + "unaffected": 24720, + "##sius": 24721, + "annabelle": 24722, + "flopped": 24723, + "sloping": 24724, + "##litz": 24725, + "dreamer": 24726, + "interceptor": 24727, + "vu": 24728, + "##loh": 24729, + "consecration": 24730, + "copying": 24731, + "messaging": 24732, + "breaker": 24733, + "climates": 24734, + "hospitalized": 24735, + "1752": 24736, + "torino": 24737, + "afternoons": 24738, + "winfield": 24739, + "witnessing": 24740, + "##teacher": 24741, + "breakers": 24742, + "choirs": 24743, + "sawmill": 24744, + "coldly": 24745, + "##ege": 24746, + "sipping": 24747, + "haste": 24748, + "uninhabited": 24749, + "conical": 24750, + "bibliography": 24751, + "pamphlets": 24752, + "severn": 24753, + "edict": 24754, + "##oca": 24755, + "deux": 24756, + "illnesses": 24757, + "grips": 24758, + "##pl": 24759, + "rehearsals": 24760, + "sis": 24761, + "thinkers": 24762, + "tame": 24763, + "##keepers": 24764, + "1690": 24765, + "acacia": 24766, + "reformer": 24767, + "##osed": 24768, + "##rys": 24769, + "shuffling": 24770, + "##iring": 24771, + "##shima": 24772, + "eastbound": 24773, + "ionic": 24774, + "rhea": 24775, + "flees": 24776, + "littered": 24777, + "##oum": 24778, + "rocker": 24779, + "vomiting": 24780, + "groaning": 24781, + "champ": 24782, + "overwhelmingly": 24783, + "civilizations": 24784, + "paces": 24785, + "sloop": 24786, + "adoptive": 24787, + "##tish": 24788, + "skaters": 24789, + "##vres": 24790, + "aiding": 24791, + "mango": 24792, + "##joy": 24793, + "nikola": 24794, + "shriek": 24795, + "##ignon": 24796, + "pharmaceuticals": 24797, + "##mg": 24798, + "tuna": 24799, + "calvert": 24800, + "gustavo": 24801, + "stocked": 24802, + "yearbook": 24803, + "##urai": 24804, + "##mana": 24805, + "computed": 24806, + "subsp": 24807, + "riff": 24808, + "hanoi": 24809, + "kelvin": 24810, + "hamid": 24811, + "moors": 24812, + "pastures": 24813, + "summons": 24814, + "jihad": 24815, + "nectar": 24816, + "##ctors": 24817, + "bayou": 24818, + "untitled": 24819, + "pleasing": 24820, + "vastly": 24821, + "republics": 24822, + "intellect": 24823, + "##η": 24824, + "##ulio": 24825, + "##tou": 24826, + "crumbling": 24827, + "stylistic": 24828, + "sb": 24829, + "##ی": 24830, + "consolation": 24831, + "frequented": 24832, + "h₂o": 24833, + "walden": 24834, + "widows": 24835, + "##iens": 24836, + "404": 24837, + "##ignment": 24838, + "chunks": 24839, + "improves": 24840, + "288": 24841, + "grit": 24842, + "recited": 24843, + "##dev": 24844, + "snarl": 24845, + "sociological": 24846, + "##arte": 24847, + "##gul": 24848, + "inquired": 24849, + "##held": 24850, + "bruise": 24851, + "clube": 24852, + "consultancy": 24853, + "homogeneous": 24854, + "hornets": 24855, + "multiplication": 24856, + "pasta": 24857, + "prick": 24858, + "savior": 24859, + "##grin": 24860, + "##kou": 24861, + "##phile": 24862, + "yoon": 24863, + "##gara": 24864, + "grimes": 24865, + "vanishing": 24866, + "cheering": 24867, + "reacting": 24868, + "bn": 24869, + "distillery": 24870, + "##quisite": 24871, + "##vity": 24872, + "coe": 24873, + "dockyard": 24874, + "massif": 24875, + "##jord": 24876, + "escorts": 24877, + "voss": 24878, + "##valent": 24879, + "byte": 24880, + "chopped": 24881, + "hawke": 24882, + "illusions": 24883, + "workings": 24884, + "floats": 24885, + "##koto": 24886, + "##vac": 24887, + "kv": 24888, + "annapolis": 24889, + "madden": 24890, + "##onus": 24891, + "alvaro": 24892, + "noctuidae": 24893, + "##cum": 24894, + "##scopic": 24895, + "avenge": 24896, + "steamboat": 24897, + "forte": 24898, + "illustrates": 24899, + "erika": 24900, + "##trip": 24901, + "570": 24902, + "dew": 24903, + "nationalities": 24904, + "bran": 24905, + "manifested": 24906, + "thirsty": 24907, + "diversified": 24908, + "muscled": 24909, + "reborn": 24910, + "##standing": 24911, + "arson": 24912, + "##lessness": 24913, + "##dran": 24914, + "##logram": 24915, + "##boys": 24916, + "##kushima": 24917, + "##vious": 24918, + "willoughby": 24919, + "##phobia": 24920, + "286": 24921, + "alsace": 24922, + "dashboard": 24923, + "yuki": 24924, + "##chai": 24925, + "granville": 24926, + "myspace": 24927, + "publicized": 24928, + "tricked": 24929, + "##gang": 24930, + "adjective": 24931, + "##ater": 24932, + "relic": 24933, + "reorganisation": 24934, + "enthusiastically": 24935, + "indications": 24936, + "saxe": 24937, + "##lassified": 24938, + "consolidate": 24939, + "iec": 24940, + "padua": 24941, + "helplessly": 24942, + "ramps": 24943, + "renaming": 24944, + "regulars": 24945, + "pedestrians": 24946, + "accents": 24947, + "convicts": 24948, + "inaccurate": 24949, + "lowers": 24950, + "mana": 24951, + "##pati": 24952, + "barrie": 24953, + "bjp": 24954, + "outta": 24955, + "someplace": 24956, + "berwick": 24957, + "flanking": 24958, + "invoked": 24959, + "marrow": 24960, + "sparsely": 24961, + "excerpts": 24962, + "clothed": 24963, + "rei": 24964, + "##ginal": 24965, + "wept": 24966, + "##straße": 24967, + "##vish": 24968, + "alexa": 24969, + "excel": 24970, + "##ptive": 24971, + "membranes": 24972, + "aquitaine": 24973, + "creeks": 24974, + "cutler": 24975, + "sheppard": 24976, + "implementations": 24977, + "ns": 24978, + "##dur": 24979, + "fragrance": 24980, + "budge": 24981, + "concordia": 24982, + "magnesium": 24983, + "marcelo": 24984, + "##antes": 24985, + "gladly": 24986, + "vibrating": 24987, + "##rral": 24988, + "##ggles": 24989, + "montrose": 24990, + "##omba": 24991, + "lew": 24992, + "seamus": 24993, + "1630": 24994, + "cocky": 24995, + "##ament": 24996, + "##uen": 24997, + "bjorn": 24998, + "##rrick": 24999, + "fielder": 25000, + "fluttering": 25001, + "##lase": 25002, + "methyl": 25003, + "kimberley": 25004, + "mcdowell": 25005, + "reductions": 25006, + "barbed": 25007, + "##jic": 25008, + "##tonic": 25009, + "aeronautical": 25010, + "condensed": 25011, + "distracting": 25012, + "##promising": 25013, + "huffed": 25014, + "##cala": 25015, + "##sle": 25016, + "claudius": 25017, + "invincible": 25018, + "missy": 25019, + "pious": 25020, + "balthazar": 25021, + "ci": 25022, + "##lang": 25023, + "butte": 25024, + "combo": 25025, + "orson": 25026, + "##dication": 25027, + "myriad": 25028, + "1707": 25029, + "silenced": 25030, + "##fed": 25031, + "##rh": 25032, + "coco": 25033, + "netball": 25034, + "yourselves": 25035, + "##oza": 25036, + "clarify": 25037, + "heller": 25038, + "peg": 25039, + "durban": 25040, + "etudes": 25041, + "offender": 25042, + "roast": 25043, + "blackmail": 25044, + "curvature": 25045, + "##woods": 25046, + "vile": 25047, + "309": 25048, + "illicit": 25049, + "suriname": 25050, + "##linson": 25051, + "overture": 25052, + "1685": 25053, + "bubbling": 25054, + "gymnast": 25055, + "tucking": 25056, + "##mming": 25057, + "##ouin": 25058, + "maldives": 25059, + "##bala": 25060, + "gurney": 25061, + "##dda": 25062, + "##eased": 25063, + "##oides": 25064, + "backside": 25065, + "pinto": 25066, + "jars": 25067, + "racehorse": 25068, + "tending": 25069, + "##rdial": 25070, + "baronetcy": 25071, + "wiener": 25072, + "duly": 25073, + "##rke": 25074, + "barbarian": 25075, + "cupping": 25076, + "flawed": 25077, + "##thesis": 25078, + "bertha": 25079, + "pleistocene": 25080, + "puddle": 25081, + "swearing": 25082, + "##nob": 25083, + "##tically": 25084, + "fleeting": 25085, + "prostate": 25086, + "amulet": 25087, + "educating": 25088, + "##mined": 25089, + "##iti": 25090, + "##tler": 25091, + "75th": 25092, + "jens": 25093, + "respondents": 25094, + "analytics": 25095, + "cavaliers": 25096, + "papacy": 25097, + "raju": 25098, + "##iente": 25099, + "##ulum": 25100, + "##tip": 25101, + "funnel": 25102, + "271": 25103, + "disneyland": 25104, + "##lley": 25105, + "sociologist": 25106, + "##iam": 25107, + "2500": 25108, + "faulkner": 25109, + "louvre": 25110, + "menon": 25111, + "##dson": 25112, + "276": 25113, + "##ower": 25114, + "afterlife": 25115, + "mannheim": 25116, + "peptide": 25117, + "referees": 25118, + "comedians": 25119, + "meaningless": 25120, + "##anger": 25121, + "##laise": 25122, + "fabrics": 25123, + "hurley": 25124, + "renal": 25125, + "sleeps": 25126, + "##bour": 25127, + "##icle": 25128, + "breakout": 25129, + "kristin": 25130, + "roadside": 25131, + "animator": 25132, + "clover": 25133, + "disdain": 25134, + "unsafe": 25135, + "redesign": 25136, + "##urity": 25137, + "firth": 25138, + "barnsley": 25139, + "portage": 25140, + "reset": 25141, + "narrows": 25142, + "268": 25143, + "commandos": 25144, + "expansive": 25145, + "speechless": 25146, + "tubular": 25147, + "##lux": 25148, + "essendon": 25149, + "eyelashes": 25150, + "smashwords": 25151, + "##yad": 25152, + "##bang": 25153, + "##claim": 25154, + "craved": 25155, + "sprinted": 25156, + "chet": 25157, + "somme": 25158, + "astor": 25159, + "wrocław": 25160, + "orton": 25161, + "266": 25162, + "bane": 25163, + "##erving": 25164, + "##uing": 25165, + "mischief": 25166, + "##amps": 25167, + "##sund": 25168, + "scaling": 25169, + "terre": 25170, + "##xious": 25171, + "impairment": 25172, + "offenses": 25173, + "undermine": 25174, + "moi": 25175, + "soy": 25176, + "contiguous": 25177, + "arcadia": 25178, + "inuit": 25179, + "seam": 25180, + "##tops": 25181, + "macbeth": 25182, + "rebelled": 25183, + "##icative": 25184, + "##iot": 25185, + "590": 25186, + "elaborated": 25187, + "frs": 25188, + "uniformed": 25189, + "##dberg": 25190, + "259": 25191, + "powerless": 25192, + "priscilla": 25193, + "stimulated": 25194, + "980": 25195, + "qc": 25196, + "arboretum": 25197, + "frustrating": 25198, + "trieste": 25199, + "bullock": 25200, + "##nified": 25201, + "enriched": 25202, + "glistening": 25203, + "intern": 25204, + "##adia": 25205, + "locus": 25206, + "nouvelle": 25207, + "ollie": 25208, + "ike": 25209, + "lash": 25210, + "starboard": 25211, + "ee": 25212, + "tapestry": 25213, + "headlined": 25214, + "hove": 25215, + "rigged": 25216, + "##vite": 25217, + "pollock": 25218, + "##yme": 25219, + "thrive": 25220, + "clustered": 25221, + "cas": 25222, + "roi": 25223, + "gleamed": 25224, + "olympiad": 25225, + "##lino": 25226, + "pressured": 25227, + "regimes": 25228, + "##hosis": 25229, + "##lick": 25230, + "ripley": 25231, + "##ophone": 25232, + "kickoff": 25233, + "gallon": 25234, + "rockwell": 25235, + "##arable": 25236, + "crusader": 25237, + "glue": 25238, + "revolutions": 25239, + "scrambling": 25240, + "1714": 25241, + "grover": 25242, + "##jure": 25243, + "englishman": 25244, + "aztec": 25245, + "263": 25246, + "contemplating": 25247, + "coven": 25248, + "ipad": 25249, + "preach": 25250, + "triumphant": 25251, + "tufts": 25252, + "##esian": 25253, + "rotational": 25254, + "##phus": 25255, + "328": 25256, + "falkland": 25257, + "##brates": 25258, + "strewn": 25259, + "clarissa": 25260, + "rejoin": 25261, + "environmentally": 25262, + "glint": 25263, + "banded": 25264, + "drenched": 25265, + "moat": 25266, + "albanians": 25267, + "johor": 25268, + "rr": 25269, + "maestro": 25270, + "malley": 25271, + "nouveau": 25272, + "shaded": 25273, + "taxonomy": 25274, + "v6": 25275, + "adhere": 25276, + "bunk": 25277, + "airfields": 25278, + "##ritan": 25279, + "1741": 25280, + "encompass": 25281, + "remington": 25282, + "tran": 25283, + "##erative": 25284, + "amelie": 25285, + "mazda": 25286, + "friar": 25287, + "morals": 25288, + "passions": 25289, + "##zai": 25290, + "breadth": 25291, + "vis": 25292, + "##hae": 25293, + "argus": 25294, + "burnham": 25295, + "caressing": 25296, + "insider": 25297, + "rudd": 25298, + "##imov": 25299, + "##mini": 25300, + "##rso": 25301, + "italianate": 25302, + "murderous": 25303, + "textual": 25304, + "wainwright": 25305, + "armada": 25306, + "bam": 25307, + "weave": 25308, + "timer": 25309, + "##taken": 25310, + "##nh": 25311, + "fra": 25312, + "##crest": 25313, + "ardent": 25314, + "salazar": 25315, + "taps": 25316, + "tunis": 25317, + "##ntino": 25318, + "allegro": 25319, + "gland": 25320, + "philanthropic": 25321, + "##chester": 25322, + "implication": 25323, + "##optera": 25324, + "esq": 25325, + "judas": 25326, + "noticeably": 25327, + "wynn": 25328, + "##dara": 25329, + "inched": 25330, + "indexed": 25331, + "crises": 25332, + "villiers": 25333, + "bandit": 25334, + "royalties": 25335, + "patterned": 25336, + "cupboard": 25337, + "interspersed": 25338, + "accessory": 25339, + "isla": 25340, + "kendrick": 25341, + "entourage": 25342, + "stitches": 25343, + "##esthesia": 25344, + "headwaters": 25345, + "##ior": 25346, + "interlude": 25347, + "distraught": 25348, + "draught": 25349, + "1727": 25350, + "##basket": 25351, + "biased": 25352, + "sy": 25353, + "transient": 25354, + "triad": 25355, + "subgenus": 25356, + "adapting": 25357, + "kidd": 25358, + "shortstop": 25359, + "##umatic": 25360, + "dimly": 25361, + "spiked": 25362, + "mcleod": 25363, + "reprint": 25364, + "nellie": 25365, + "pretoria": 25366, + "windmill": 25367, + "##cek": 25368, + "singled": 25369, + "##mps": 25370, + "273": 25371, + "reunite": 25372, + "##orous": 25373, + "747": 25374, + "bankers": 25375, + "outlying": 25376, + "##omp": 25377, + "##ports": 25378, + "##tream": 25379, + "apologies": 25380, + "cosmetics": 25381, + "patsy": 25382, + "##deh": 25383, + "##ocks": 25384, + "##yson": 25385, + "bender": 25386, + "nantes": 25387, + "serene": 25388, + "##nad": 25389, + "lucha": 25390, + "mmm": 25391, + "323": 25392, + "##cius": 25393, + "##gli": 25394, + "cmll": 25395, + "coinage": 25396, + "nestor": 25397, + "juarez": 25398, + "##rook": 25399, + "smeared": 25400, + "sprayed": 25401, + "twitching": 25402, + "sterile": 25403, + "irina": 25404, + "embodied": 25405, + "juveniles": 25406, + "enveloped": 25407, + "miscellaneous": 25408, + "cancers": 25409, + "dq": 25410, + "gulped": 25411, + "luisa": 25412, + "crested": 25413, + "swat": 25414, + "donegal": 25415, + "ref": 25416, + "##anov": 25417, + "##acker": 25418, + "hearst": 25419, + "mercantile": 25420, + "##lika": 25421, + "doorbell": 25422, + "ua": 25423, + "vicki": 25424, + "##alla": 25425, + "##som": 25426, + "bilbao": 25427, + "psychologists": 25428, + "stryker": 25429, + "sw": 25430, + "horsemen": 25431, + "turkmenistan": 25432, + "wits": 25433, + "##national": 25434, + "anson": 25435, + "mathew": 25436, + "screenings": 25437, + "##umb": 25438, + "rihanna": 25439, + "##agne": 25440, + "##nessy": 25441, + "aisles": 25442, + "##iani": 25443, + "##osphere": 25444, + "hines": 25445, + "kenton": 25446, + "saskatoon": 25447, + "tasha": 25448, + "truncated": 25449, + "##champ": 25450, + "##itan": 25451, + "mildred": 25452, + "advises": 25453, + "fredrik": 25454, + "interpreting": 25455, + "inhibitors": 25456, + "##athi": 25457, + "spectroscopy": 25458, + "##hab": 25459, + "##kong": 25460, + "karim": 25461, + "panda": 25462, + "##oia": 25463, + "##nail": 25464, + "##vc": 25465, + "conqueror": 25466, + "kgb": 25467, + "leukemia": 25468, + "##dity": 25469, + "arrivals": 25470, + "cheered": 25471, + "pisa": 25472, + "phosphorus": 25473, + "shielded": 25474, + "##riated": 25475, + "mammal": 25476, + "unitarian": 25477, + "urgently": 25478, + "chopin": 25479, + "sanitary": 25480, + "##mission": 25481, + "spicy": 25482, + "drugged": 25483, + "hinges": 25484, + "##tort": 25485, + "tipping": 25486, + "trier": 25487, + "impoverished": 25488, + "westchester": 25489, + "##caster": 25490, + "267": 25491, + "epoch": 25492, + "nonstop": 25493, + "##gman": 25494, + "##khov": 25495, + "aromatic": 25496, + "centrally": 25497, + "cerro": 25498, + "##tively": 25499, + "##vio": 25500, + "billions": 25501, + "modulation": 25502, + "sedimentary": 25503, + "283": 25504, + "facilitating": 25505, + "outrageous": 25506, + "goldstein": 25507, + "##eak": 25508, + "##kt": 25509, + "ld": 25510, + "maitland": 25511, + "penultimate": 25512, + "pollard": 25513, + "##dance": 25514, + "fleets": 25515, + "spaceship": 25516, + "vertebrae": 25517, + "##nig": 25518, + "alcoholism": 25519, + "als": 25520, + "recital": 25521, + "##bham": 25522, + "##ference": 25523, + "##omics": 25524, + "m2": 25525, + "##bm": 25526, + "trois": 25527, + "##tropical": 25528, + "##в": 25529, + "commemorates": 25530, + "##meric": 25531, + "marge": 25532, + "##raction": 25533, + "1643": 25534, + "670": 25535, + "cosmetic": 25536, + "ravaged": 25537, + "##ige": 25538, + "catastrophe": 25539, + "eng": 25540, + "##shida": 25541, + "albrecht": 25542, + "arterial": 25543, + "bellamy": 25544, + "decor": 25545, + "harmon": 25546, + "##rde": 25547, + "bulbs": 25548, + "synchronized": 25549, + "vito": 25550, + "easiest": 25551, + "shetland": 25552, + "shielding": 25553, + "wnba": 25554, + "##glers": 25555, + "##ssar": 25556, + "##riam": 25557, + "brianna": 25558, + "cumbria": 25559, + "##aceous": 25560, + "##rard": 25561, + "cores": 25562, + "thayer": 25563, + "##nsk": 25564, + "brood": 25565, + "hilltop": 25566, + "luminous": 25567, + "carts": 25568, + "keynote": 25569, + "larkin": 25570, + "logos": 25571, + "##cta": 25572, + "##ا": 25573, + "##mund": 25574, + "##quay": 25575, + "lilith": 25576, + "tinted": 25577, + "277": 25578, + "wrestle": 25579, + "mobilization": 25580, + "##uses": 25581, + "sequential": 25582, + "siam": 25583, + "bloomfield": 25584, + "takahashi": 25585, + "274": 25586, + "##ieving": 25587, + "presenters": 25588, + "ringo": 25589, + "blazed": 25590, + "witty": 25591, + "##oven": 25592, + "##ignant": 25593, + "devastation": 25594, + "haydn": 25595, + "harmed": 25596, + "newt": 25597, + "therese": 25598, + "##peed": 25599, + "gershwin": 25600, + "molina": 25601, + "rabbis": 25602, + "sudanese": 25603, + "001": 25604, + "innate": 25605, + "restarted": 25606, + "##sack": 25607, + "##fus": 25608, + "slices": 25609, + "wb": 25610, + "##shah": 25611, + "enroll": 25612, + "hypothetical": 25613, + "hysterical": 25614, + "1743": 25615, + "fabio": 25616, + "indefinite": 25617, + "warped": 25618, + "##hg": 25619, + "exchanging": 25620, + "525": 25621, + "unsuitable": 25622, + "##sboro": 25623, + "gallo": 25624, + "1603": 25625, + "bret": 25626, + "cobalt": 25627, + "homemade": 25628, + "##hunter": 25629, + "mx": 25630, + "operatives": 25631, + "##dhar": 25632, + "terraces": 25633, + "durable": 25634, + "latch": 25635, + "pens": 25636, + "whorls": 25637, + "##ctuated": 25638, + "##eaux": 25639, + "billing": 25640, + "ligament": 25641, + "succumbed": 25642, + "##gly": 25643, + "regulators": 25644, + "spawn": 25645, + "##brick": 25646, + "##stead": 25647, + "filmfare": 25648, + "rochelle": 25649, + "##nzo": 25650, + "1725": 25651, + "circumstance": 25652, + "saber": 25653, + "supplements": 25654, + "##nsky": 25655, + "##tson": 25656, + "crowe": 25657, + "wellesley": 25658, + "carrot": 25659, + "##9th": 25660, + "##movable": 25661, + "primate": 25662, + "drury": 25663, + "sincerely": 25664, + "topical": 25665, + "##mad": 25666, + "##rao": 25667, + "callahan": 25668, + "kyiv": 25669, + "smarter": 25670, + "tits": 25671, + "undo": 25672, + "##yeh": 25673, + "announcements": 25674, + "anthologies": 25675, + "barrio": 25676, + "nebula": 25677, + "##islaus": 25678, + "##shaft": 25679, + "##tyn": 25680, + "bodyguards": 25681, + "2021": 25682, + "assassinate": 25683, + "barns": 25684, + "emmett": 25685, + "scully": 25686, + "##mah": 25687, + "##yd": 25688, + "##eland": 25689, + "##tino": 25690, + "##itarian": 25691, + "demoted": 25692, + "gorman": 25693, + "lashed": 25694, + "prized": 25695, + "adventist": 25696, + "writ": 25697, + "##gui": 25698, + "alla": 25699, + "invertebrates": 25700, + "##ausen": 25701, + "1641": 25702, + "amman": 25703, + "1742": 25704, + "align": 25705, + "healy": 25706, + "redistribution": 25707, + "##gf": 25708, + "##rize": 25709, + "insulation": 25710, + "##drop": 25711, + "adherents": 25712, + "hezbollah": 25713, + "vitro": 25714, + "ferns": 25715, + "yanking": 25716, + "269": 25717, + "php": 25718, + "registering": 25719, + "uppsala": 25720, + "cheerleading": 25721, + "confines": 25722, + "mischievous": 25723, + "tully": 25724, + "##ross": 25725, + "49th": 25726, + "docked": 25727, + "roam": 25728, + "stipulated": 25729, + "pumpkin": 25730, + "##bry": 25731, + "prompt": 25732, + "##ezer": 25733, + "blindly": 25734, + "shuddering": 25735, + "craftsmen": 25736, + "frail": 25737, + "scented": 25738, + "katharine": 25739, + "scramble": 25740, + "shaggy": 25741, + "sponge": 25742, + "helix": 25743, + "zaragoza": 25744, + "279": 25745, + "##52": 25746, + "43rd": 25747, + "backlash": 25748, + "fontaine": 25749, + "seizures": 25750, + "posse": 25751, + "cowan": 25752, + "nonfiction": 25753, + "telenovela": 25754, + "wwii": 25755, + "hammered": 25756, + "undone": 25757, + "##gpur": 25758, + "encircled": 25759, + "irs": 25760, + "##ivation": 25761, + "artefacts": 25762, + "oneself": 25763, + "searing": 25764, + "smallpox": 25765, + "##belle": 25766, + "##osaurus": 25767, + "shandong": 25768, + "breached": 25769, + "upland": 25770, + "blushing": 25771, + "rankin": 25772, + "infinitely": 25773, + "psyche": 25774, + "tolerated": 25775, + "docking": 25776, + "evicted": 25777, + "##col": 25778, + "unmarked": 25779, + "##lving": 25780, + "gnome": 25781, + "lettering": 25782, + "litres": 25783, + "musique": 25784, + "##oint": 25785, + "benevolent": 25786, + "##jal": 25787, + "blackened": 25788, + "##anna": 25789, + "mccall": 25790, + "racers": 25791, + "tingle": 25792, + "##ocene": 25793, + "##orestation": 25794, + "introductions": 25795, + "radically": 25796, + "292": 25797, + "##hiff": 25798, + "##باد": 25799, + "1610": 25800, + "1739": 25801, + "munchen": 25802, + "plead": 25803, + "##nka": 25804, + "condo": 25805, + "scissors": 25806, + "##sight": 25807, + "##tens": 25808, + "apprehension": 25809, + "##cey": 25810, + "##yin": 25811, + "hallmark": 25812, + "watering": 25813, + "formulas": 25814, + "sequels": 25815, + "##llas": 25816, + "aggravated": 25817, + "bae": 25818, + "commencing": 25819, + "##building": 25820, + "enfield": 25821, + "prohibits": 25822, + "marne": 25823, + "vedic": 25824, + "civilized": 25825, + "euclidean": 25826, + "jagger": 25827, + "beforehand": 25828, + "blasts": 25829, + "dumont": 25830, + "##arney": 25831, + "##nem": 25832, + "740": 25833, + "conversions": 25834, + "hierarchical": 25835, + "rios": 25836, + "simulator": 25837, + "##dya": 25838, + "##lellan": 25839, + "hedges": 25840, + "oleg": 25841, + "thrusts": 25842, + "shadowed": 25843, + "darby": 25844, + "maximize": 25845, + "1744": 25846, + "gregorian": 25847, + "##nded": 25848, + "##routed": 25849, + "sham": 25850, + "unspecified": 25851, + "##hog": 25852, + "emory": 25853, + "factual": 25854, + "##smo": 25855, + "##tp": 25856, + "fooled": 25857, + "##rger": 25858, + "ortega": 25859, + "wellness": 25860, + "marlon": 25861, + "##oton": 25862, + "##urance": 25863, + "casket": 25864, + "keating": 25865, + "ley": 25866, + "enclave": 25867, + "##ayan": 25868, + "char": 25869, + "influencing": 25870, + "jia": 25871, + "##chenko": 25872, + "412": 25873, + "ammonia": 25874, + "erebidae": 25875, + "incompatible": 25876, + "violins": 25877, + "cornered": 25878, + "##arat": 25879, + "grooves": 25880, + "astronauts": 25881, + "columbian": 25882, + "rampant": 25883, + "fabrication": 25884, + "kyushu": 25885, + "mahmud": 25886, + "vanish": 25887, + "##dern": 25888, + "mesopotamia": 25889, + "##lete": 25890, + "ict": 25891, + "##rgen": 25892, + "caspian": 25893, + "kenji": 25894, + "pitted": 25895, + "##vered": 25896, + "999": 25897, + "grimace": 25898, + "roanoke": 25899, + "tchaikovsky": 25900, + "twinned": 25901, + "##analysis": 25902, + "##awan": 25903, + "xinjiang": 25904, + "arias": 25905, + "clemson": 25906, + "kazakh": 25907, + "sizable": 25908, + "1662": 25909, + "##khand": 25910, + "##vard": 25911, + "plunge": 25912, + "tatum": 25913, + "vittorio": 25914, + "##nden": 25915, + "cholera": 25916, + "##dana": 25917, + "##oper": 25918, + "bracing": 25919, + "indifference": 25920, + "projectile": 25921, + "superliga": 25922, + "##chee": 25923, + "realises": 25924, + "upgrading": 25925, + "299": 25926, + "porte": 25927, + "retribution": 25928, + "##vies": 25929, + "nk": 25930, + "stil": 25931, + "##resses": 25932, + "ama": 25933, + "bureaucracy": 25934, + "blackberry": 25935, + "bosch": 25936, + "testosterone": 25937, + "collapses": 25938, + "greer": 25939, + "##pathic": 25940, + "ioc": 25941, + "fifties": 25942, + "malls": 25943, + "##erved": 25944, + "bao": 25945, + "baskets": 25946, + "adolescents": 25947, + "siegfried": 25948, + "##osity": 25949, + "##tosis": 25950, + "mantra": 25951, + "detecting": 25952, + "existent": 25953, + "fledgling": 25954, + "##cchi": 25955, + "dissatisfied": 25956, + "gan": 25957, + "telecommunication": 25958, + "mingled": 25959, + "sobbed": 25960, + "6000": 25961, + "controversies": 25962, + "outdated": 25963, + "taxis": 25964, + "##raus": 25965, + "fright": 25966, + "slams": 25967, + "##lham": 25968, + "##fect": 25969, + "##tten": 25970, + "detectors": 25971, + "fetal": 25972, + "tanned": 25973, + "##uw": 25974, + "fray": 25975, + "goth": 25976, + "olympian": 25977, + "skipping": 25978, + "mandates": 25979, + "scratches": 25980, + "sheng": 25981, + "unspoken": 25982, + "hyundai": 25983, + "tracey": 25984, + "hotspur": 25985, + "restrictive": 25986, + "##buch": 25987, + "americana": 25988, + "mundo": 25989, + "##bari": 25990, + "burroughs": 25991, + "diva": 25992, + "vulcan": 25993, + "##6th": 25994, + "distinctions": 25995, + "thumping": 25996, + "##ngen": 25997, + "mikey": 25998, + "sheds": 25999, + "fide": 26000, + "rescues": 26001, + "springsteen": 26002, + "vested": 26003, + "valuation": 26004, + "##ece": 26005, + "##ely": 26006, + "pinnacle": 26007, + "rake": 26008, + "sylvie": 26009, + "##edo": 26010, + "almond": 26011, + "quivering": 26012, + "##irus": 26013, + "alteration": 26014, + "faltered": 26015, + "##wad": 26016, + "51st": 26017, + "hydra": 26018, + "ticked": 26019, + "##kato": 26020, + "recommends": 26021, + "##dicated": 26022, + "antigua": 26023, + "arjun": 26024, + "stagecoach": 26025, + "wilfred": 26026, + "trickle": 26027, + "pronouns": 26028, + "##pon": 26029, + "aryan": 26030, + "nighttime": 26031, + "##anian": 26032, + "gall": 26033, + "pea": 26034, + "stitch": 26035, + "##hei": 26036, + "leung": 26037, + "milos": 26038, + "##dini": 26039, + "eritrea": 26040, + "nexus": 26041, + "starved": 26042, + "snowfall": 26043, + "kant": 26044, + "parasitic": 26045, + "cot": 26046, + "discus": 26047, + "hana": 26048, + "strikers": 26049, + "appleton": 26050, + "kitchens": 26051, + "##erina": 26052, + "##partisan": 26053, + "##itha": 26054, + "##vius": 26055, + "disclose": 26056, + "metis": 26057, + "##channel": 26058, + "1701": 26059, + "tesla": 26060, + "##vera": 26061, + "fitch": 26062, + "1735": 26063, + "blooded": 26064, + "##tila": 26065, + "decimal": 26066, + "##tang": 26067, + "##bai": 26068, + "cyclones": 26069, + "eun": 26070, + "bottled": 26071, + "peas": 26072, + "pensacola": 26073, + "basha": 26074, + "bolivian": 26075, + "crabs": 26076, + "boil": 26077, + "lanterns": 26078, + "partridge": 26079, + "roofed": 26080, + "1645": 26081, + "necks": 26082, + "##phila": 26083, + "opined": 26084, + "patting": 26085, + "##kla": 26086, + "##lland": 26087, + "chuckles": 26088, + "volta": 26089, + "whereupon": 26090, + "##nche": 26091, + "devout": 26092, + "euroleague": 26093, + "suicidal": 26094, + "##dee": 26095, + "inherently": 26096, + "involuntary": 26097, + "knitting": 26098, + "nasser": 26099, + "##hide": 26100, + "puppets": 26101, + "colourful": 26102, + "courageous": 26103, + "southend": 26104, + "stills": 26105, + "miraculous": 26106, + "hodgson": 26107, + "richer": 26108, + "rochdale": 26109, + "ethernet": 26110, + "greta": 26111, + "uniting": 26112, + "prism": 26113, + "umm": 26114, + "##haya": 26115, + "##itical": 26116, + "##utation": 26117, + "deterioration": 26118, + "pointe": 26119, + "prowess": 26120, + "##ropriation": 26121, + "lids": 26122, + "scranton": 26123, + "billings": 26124, + "subcontinent": 26125, + "##koff": 26126, + "##scope": 26127, + "brute": 26128, + "kellogg": 26129, + "psalms": 26130, + "degraded": 26131, + "##vez": 26132, + "stanisław": 26133, + "##ructured": 26134, + "ferreira": 26135, + "pun": 26136, + "astonishing": 26137, + "gunnar": 26138, + "##yat": 26139, + "arya": 26140, + "prc": 26141, + "gottfried": 26142, + "##tight": 26143, + "excursion": 26144, + "##ographer": 26145, + "dina": 26146, + "##quil": 26147, + "##nare": 26148, + "huffington": 26149, + "illustrious": 26150, + "wilbur": 26151, + "gundam": 26152, + "verandah": 26153, + "##zard": 26154, + "naacp": 26155, + "##odle": 26156, + "constructive": 26157, + "fjord": 26158, + "kade": 26159, + "##naud": 26160, + "generosity": 26161, + "thrilling": 26162, + "baseline": 26163, + "cayman": 26164, + "frankish": 26165, + "plastics": 26166, + "accommodations": 26167, + "zoological": 26168, + "##fting": 26169, + "cedric": 26170, + "qb": 26171, + "motorized": 26172, + "##dome": 26173, + "##otted": 26174, + "squealed": 26175, + "tackled": 26176, + "canucks": 26177, + "budgets": 26178, + "situ": 26179, + "asthma": 26180, + "dail": 26181, + "gabled": 26182, + "grasslands": 26183, + "whimpered": 26184, + "writhing": 26185, + "judgments": 26186, + "##65": 26187, + "minnie": 26188, + "pv": 26189, + "##carbon": 26190, + "bananas": 26191, + "grille": 26192, + "domes": 26193, + "monique": 26194, + "odin": 26195, + "maguire": 26196, + "markham": 26197, + "tierney": 26198, + "##estra": 26199, + "##chua": 26200, + "libel": 26201, + "poke": 26202, + "speedy": 26203, + "atrium": 26204, + "laval": 26205, + "notwithstanding": 26206, + "##edly": 26207, + "fai": 26208, + "kala": 26209, + "##sur": 26210, + "robb": 26211, + "##sma": 26212, + "listings": 26213, + "luz": 26214, + "supplementary": 26215, + "tianjin": 26216, + "##acing": 26217, + "enzo": 26218, + "jd": 26219, + "ric": 26220, + "scanner": 26221, + "croats": 26222, + "transcribed": 26223, + "##49": 26224, + "arden": 26225, + "cv": 26226, + "##hair": 26227, + "##raphy": 26228, + "##lver": 26229, + "##uy": 26230, + "357": 26231, + "seventies": 26232, + "staggering": 26233, + "alam": 26234, + "horticultural": 26235, + "hs": 26236, + "regression": 26237, + "timbers": 26238, + "blasting": 26239, + "##ounded": 26240, + "montagu": 26241, + "manipulating": 26242, + "##cit": 26243, + "catalytic": 26244, + "1550": 26245, + "troopers": 26246, + "##meo": 26247, + "condemnation": 26248, + "fitzpatrick": 26249, + "##oire": 26250, + "##roved": 26251, + "inexperienced": 26252, + "1670": 26253, + "castes": 26254, + "##lative": 26255, + "outing": 26256, + "314": 26257, + "dubois": 26258, + "flicking": 26259, + "quarrel": 26260, + "ste": 26261, + "learners": 26262, + "1625": 26263, + "iq": 26264, + "whistled": 26265, + "##class": 26266, + "282": 26267, + "classify": 26268, + "tariffs": 26269, + "temperament": 26270, + "355": 26271, + "folly": 26272, + "liszt": 26273, + "##yles": 26274, + "immersed": 26275, + "jordanian": 26276, + "ceasefire": 26277, + "apparel": 26278, + "extras": 26279, + "maru": 26280, + "fished": 26281, + "##bio": 26282, + "harta": 26283, + "stockport": 26284, + "assortment": 26285, + "craftsman": 26286, + "paralysis": 26287, + "transmitters": 26288, + "##cola": 26289, + "blindness": 26290, + "##wk": 26291, + "fatally": 26292, + "proficiency": 26293, + "solemnly": 26294, + "##orno": 26295, + "repairing": 26296, + "amore": 26297, + "groceries": 26298, + "ultraviolet": 26299, + "##chase": 26300, + "schoolhouse": 26301, + "##tua": 26302, + "resurgence": 26303, + "nailed": 26304, + "##otype": 26305, + "##×": 26306, + "ruse": 26307, + "saliva": 26308, + "diagrams": 26309, + "##tructing": 26310, + "albans": 26311, + "rann": 26312, + "thirties": 26313, + "1b": 26314, + "antennas": 26315, + "hilarious": 26316, + "cougars": 26317, + "paddington": 26318, + "stats": 26319, + "##eger": 26320, + "breakaway": 26321, + "ipod": 26322, + "reza": 26323, + "authorship": 26324, + "prohibiting": 26325, + "scoffed": 26326, + "##etz": 26327, + "##ttle": 26328, + "conscription": 26329, + "defected": 26330, + "trondheim": 26331, + "##fires": 26332, + "ivanov": 26333, + "keenan": 26334, + "##adan": 26335, + "##ciful": 26336, + "##fb": 26337, + "##slow": 26338, + "locating": 26339, + "##ials": 26340, + "##tford": 26341, + "cadiz": 26342, + "basalt": 26343, + "blankly": 26344, + "interned": 26345, + "rags": 26346, + "rattling": 26347, + "##tick": 26348, + "carpathian": 26349, + "reassured": 26350, + "sync": 26351, + "bum": 26352, + "guildford": 26353, + "iss": 26354, + "staunch": 26355, + "##onga": 26356, + "astronomers": 26357, + "sera": 26358, + "sofie": 26359, + "emergencies": 26360, + "susquehanna": 26361, + "##heard": 26362, + "duc": 26363, + "mastery": 26364, + "vh1": 26365, + "williamsburg": 26366, + "bayer": 26367, + "buckled": 26368, + "craving": 26369, + "##khan": 26370, + "##rdes": 26371, + "bloomington": 26372, + "##write": 26373, + "alton": 26374, + "barbecue": 26375, + "##bians": 26376, + "justine": 26377, + "##hri": 26378, + "##ndt": 26379, + "delightful": 26380, + "smartphone": 26381, + "newtown": 26382, + "photon": 26383, + "retrieval": 26384, + "peugeot": 26385, + "hissing": 26386, + "##monium": 26387, + "##orough": 26388, + "flavors": 26389, + "lighted": 26390, + "relaunched": 26391, + "tainted": 26392, + "##games": 26393, + "##lysis": 26394, + "anarchy": 26395, + "microscopic": 26396, + "hopping": 26397, + "adept": 26398, + "evade": 26399, + "evie": 26400, + "##beau": 26401, + "inhibit": 26402, + "sinn": 26403, + "adjustable": 26404, + "hurst": 26405, + "intuition": 26406, + "wilton": 26407, + "cisco": 26408, + "44th": 26409, + "lawful": 26410, + "lowlands": 26411, + "stockings": 26412, + "thierry": 26413, + "##dalen": 26414, + "##hila": 26415, + "##nai": 26416, + "fates": 26417, + "prank": 26418, + "tb": 26419, + "maison": 26420, + "lobbied": 26421, + "provocative": 26422, + "1724": 26423, + "4a": 26424, + "utopia": 26425, + "##qual": 26426, + "carbonate": 26427, + "gujarati": 26428, + "purcell": 26429, + "##rford": 26430, + "curtiss": 26431, + "##mei": 26432, + "overgrown": 26433, + "arenas": 26434, + "mediation": 26435, + "swallows": 26436, + "##rnik": 26437, + "respectful": 26438, + "turnbull": 26439, + "##hedron": 26440, + "##hope": 26441, + "alyssa": 26442, + "ozone": 26443, + "##ʻi": 26444, + "ami": 26445, + "gestapo": 26446, + "johansson": 26447, + "snooker": 26448, + "canteen": 26449, + "cuff": 26450, + "declines": 26451, + "empathy": 26452, + "stigma": 26453, + "##ags": 26454, + "##iner": 26455, + "##raine": 26456, + "taxpayers": 26457, + "gui": 26458, + "volga": 26459, + "##wright": 26460, + "##copic": 26461, + "lifespan": 26462, + "overcame": 26463, + "tattooed": 26464, + "enactment": 26465, + "giggles": 26466, + "##ador": 26467, + "##camp": 26468, + "barrington": 26469, + "bribe": 26470, + "obligatory": 26471, + "orbiting": 26472, + "peng": 26473, + "##enas": 26474, + "elusive": 26475, + "sucker": 26476, + "##vating": 26477, + "cong": 26478, + "hardship": 26479, + "empowered": 26480, + "anticipating": 26481, + "estrada": 26482, + "cryptic": 26483, + "greasy": 26484, + "detainees": 26485, + "planck": 26486, + "sudbury": 26487, + "plaid": 26488, + "dod": 26489, + "marriott": 26490, + "kayla": 26491, + "##ears": 26492, + "##vb": 26493, + "##zd": 26494, + "mortally": 26495, + "##hein": 26496, + "cognition": 26497, + "radha": 26498, + "319": 26499, + "liechtenstein": 26500, + "meade": 26501, + "richly": 26502, + "argyle": 26503, + "harpsichord": 26504, + "liberalism": 26505, + "trumpets": 26506, + "lauded": 26507, + "tyrant": 26508, + "salsa": 26509, + "tiled": 26510, + "lear": 26511, + "promoters": 26512, + "reused": 26513, + "slicing": 26514, + "trident": 26515, + "##chuk": 26516, + "##gami": 26517, + "##lka": 26518, + "cantor": 26519, + "checkpoint": 26520, + "##points": 26521, + "gaul": 26522, + "leger": 26523, + "mammalian": 26524, + "##tov": 26525, + "##aar": 26526, + "##schaft": 26527, + "doha": 26528, + "frenchman": 26529, + "nirvana": 26530, + "##vino": 26531, + "delgado": 26532, + "headlining": 26533, + "##eron": 26534, + "##iography": 26535, + "jug": 26536, + "tko": 26537, + "1649": 26538, + "naga": 26539, + "intersections": 26540, + "##jia": 26541, + "benfica": 26542, + "nawab": 26543, + "##suka": 26544, + "ashford": 26545, + "gulp": 26546, + "##deck": 26547, + "##vill": 26548, + "##rug": 26549, + "brentford": 26550, + "frazier": 26551, + "pleasures": 26552, + "dunne": 26553, + "potsdam": 26554, + "shenzhen": 26555, + "dentistry": 26556, + "##tec": 26557, + "flanagan": 26558, + "##dorff": 26559, + "##hear": 26560, + "chorale": 26561, + "dinah": 26562, + "prem": 26563, + "quezon": 26564, + "##rogated": 26565, + "relinquished": 26566, + "sutra": 26567, + "terri": 26568, + "##pani": 26569, + "flaps": 26570, + "##rissa": 26571, + "poly": 26572, + "##rnet": 26573, + "homme": 26574, + "aback": 26575, + "##eki": 26576, + "linger": 26577, + "womb": 26578, + "##kson": 26579, + "##lewood": 26580, + "doorstep": 26581, + "orthodoxy": 26582, + "threaded": 26583, + "westfield": 26584, + "##rval": 26585, + "dioceses": 26586, + "fridays": 26587, + "subsided": 26588, + "##gata": 26589, + "loyalists": 26590, + "##biotic": 26591, + "##ettes": 26592, + "letterman": 26593, + "lunatic": 26594, + "prelate": 26595, + "tenderly": 26596, + "invariably": 26597, + "souza": 26598, + "thug": 26599, + "winslow": 26600, + "##otide": 26601, + "furlongs": 26602, + "gogh": 26603, + "jeopardy": 26604, + "##runa": 26605, + "pegasus": 26606, + "##umble": 26607, + "humiliated": 26608, + "standalone": 26609, + "tagged": 26610, + "##roller": 26611, + "freshmen": 26612, + "klan": 26613, + "##bright": 26614, + "attaining": 26615, + "initiating": 26616, + "transatlantic": 26617, + "logged": 26618, + "viz": 26619, + "##uance": 26620, + "1723": 26621, + "combatants": 26622, + "intervening": 26623, + "stephane": 26624, + "chieftain": 26625, + "despised": 26626, + "grazed": 26627, + "317": 26628, + "cdc": 26629, + "galveston": 26630, + "godzilla": 26631, + "macro": 26632, + "simulate": 26633, + "##planes": 26634, + "parades": 26635, + "##esses": 26636, + "960": 26637, + "##ductive": 26638, + "##unes": 26639, + "equator": 26640, + "overdose": 26641, + "##cans": 26642, + "##hosh": 26643, + "##lifting": 26644, + "joshi": 26645, + "epstein": 26646, + "sonora": 26647, + "treacherous": 26648, + "aquatics": 26649, + "manchu": 26650, + "responsive": 26651, + "##sation": 26652, + "supervisory": 26653, + "##christ": 26654, + "##llins": 26655, + "##ibar": 26656, + "##balance": 26657, + "##uso": 26658, + "kimball": 26659, + "karlsruhe": 26660, + "mab": 26661, + "##emy": 26662, + "ignores": 26663, + "phonetic": 26664, + "reuters": 26665, + "spaghetti": 26666, + "820": 26667, + "almighty": 26668, + "danzig": 26669, + "rumbling": 26670, + "tombstone": 26671, + "designations": 26672, + "lured": 26673, + "outset": 26674, + "##felt": 26675, + "supermarkets": 26676, + "##wt": 26677, + "grupo": 26678, + "kei": 26679, + "kraft": 26680, + "susanna": 26681, + "##blood": 26682, + "comprehension": 26683, + "genealogy": 26684, + "##aghan": 26685, + "##verted": 26686, + "redding": 26687, + "##ythe": 26688, + "1722": 26689, + "bowing": 26690, + "##pore": 26691, + "##roi": 26692, + "lest": 26693, + "sharpened": 26694, + "fulbright": 26695, + "valkyrie": 26696, + "sikhs": 26697, + "##unds": 26698, + "swans": 26699, + "bouquet": 26700, + "merritt": 26701, + "##tage": 26702, + "##venting": 26703, + "commuted": 26704, + "redhead": 26705, + "clerks": 26706, + "leasing": 26707, + "cesare": 26708, + "dea": 26709, + "hazy": 26710, + "##vances": 26711, + "fledged": 26712, + "greenfield": 26713, + "servicemen": 26714, + "##gical": 26715, + "armando": 26716, + "blackout": 26717, + "dt": 26718, + "sagged": 26719, + "downloadable": 26720, + "intra": 26721, + "potion": 26722, + "pods": 26723, + "##4th": 26724, + "##mism": 26725, + "xp": 26726, + "attendants": 26727, + "gambia": 26728, + "stale": 26729, + "##ntine": 26730, + "plump": 26731, + "asteroids": 26732, + "rediscovered": 26733, + "buds": 26734, + "flea": 26735, + "hive": 26736, + "##neas": 26737, + "1737": 26738, + "classifications": 26739, + "debuts": 26740, + "##eles": 26741, + "olympus": 26742, + "scala": 26743, + "##eurs": 26744, + "##gno": 26745, + "##mute": 26746, + "hummed": 26747, + "sigismund": 26748, + "visuals": 26749, + "wiggled": 26750, + "await": 26751, + "pilasters": 26752, + "clench": 26753, + "sulfate": 26754, + "##ances": 26755, + "bellevue": 26756, + "enigma": 26757, + "trainee": 26758, + "snort": 26759, + "##sw": 26760, + "clouded": 26761, + "denim": 26762, + "##rank": 26763, + "##rder": 26764, + "churning": 26765, + "hartman": 26766, + "lodges": 26767, + "riches": 26768, + "sima": 26769, + "##missible": 26770, + "accountable": 26771, + "socrates": 26772, + "regulates": 26773, + "mueller": 26774, + "##cr": 26775, + "1702": 26776, + "avoids": 26777, + "solids": 26778, + "himalayas": 26779, + "nutrient": 26780, + "pup": 26781, + "##jevic": 26782, + "squat": 26783, + "fades": 26784, + "nec": 26785, + "##lates": 26786, + "##pina": 26787, + "##rona": 26788, + "##ου": 26789, + "privateer": 26790, + "tequila": 26791, + "##gative": 26792, + "##mpton": 26793, + "apt": 26794, + "hornet": 26795, + "immortals": 26796, + "##dou": 26797, + "asturias": 26798, + "cleansing": 26799, + "dario": 26800, + "##rries": 26801, + "##anta": 26802, + "etymology": 26803, + "servicing": 26804, + "zhejiang": 26805, + "##venor": 26806, + "##nx": 26807, + "horned": 26808, + "erasmus": 26809, + "rayon": 26810, + "relocating": 26811, + "£10": 26812, + "##bags": 26813, + "escalated": 26814, + "promenade": 26815, + "stubble": 26816, + "2010s": 26817, + "artisans": 26818, + "axial": 26819, + "liquids": 26820, + "mora": 26821, + "sho": 26822, + "yoo": 26823, + "##tsky": 26824, + "bundles": 26825, + "oldies": 26826, + "##nally": 26827, + "notification": 26828, + "bastion": 26829, + "##ths": 26830, + "sparkle": 26831, + "##lved": 26832, + "1728": 26833, + "leash": 26834, + "pathogen": 26835, + "highs": 26836, + "##hmi": 26837, + "immature": 26838, + "880": 26839, + "gonzaga": 26840, + "ignatius": 26841, + "mansions": 26842, + "monterrey": 26843, + "sweets": 26844, + "bryson": 26845, + "##loe": 26846, + "polled": 26847, + "regatta": 26848, + "brightest": 26849, + "pei": 26850, + "rosy": 26851, + "squid": 26852, + "hatfield": 26853, + "payroll": 26854, + "addict": 26855, + "meath": 26856, + "cornerback": 26857, + "heaviest": 26858, + "lodging": 26859, + "##mage": 26860, + "capcom": 26861, + "rippled": 26862, + "##sily": 26863, + "barnet": 26864, + "mayhem": 26865, + "ymca": 26866, + "snuggled": 26867, + "rousseau": 26868, + "##cute": 26869, + "blanchard": 26870, + "284": 26871, + "fragmented": 26872, + "leighton": 26873, + "chromosomes": 26874, + "risking": 26875, + "##md": 26876, + "##strel": 26877, + "##utter": 26878, + "corinne": 26879, + "coyotes": 26880, + "cynical": 26881, + "hiroshi": 26882, + "yeomanry": 26883, + "##ractive": 26884, + "ebook": 26885, + "grading": 26886, + "mandela": 26887, + "plume": 26888, + "agustin": 26889, + "magdalene": 26890, + "##rkin": 26891, + "bea": 26892, + "femme": 26893, + "trafford": 26894, + "##coll": 26895, + "##lun": 26896, + "##tance": 26897, + "52nd": 26898, + "fourier": 26899, + "upton": 26900, + "##mental": 26901, + "camilla": 26902, + "gust": 26903, + "iihf": 26904, + "islamabad": 26905, + "longevity": 26906, + "##kala": 26907, + "feldman": 26908, + "netting": 26909, + "##rization": 26910, + "endeavour": 26911, + "foraging": 26912, + "mfa": 26913, + "orr": 26914, + "##open": 26915, + "greyish": 26916, + "contradiction": 26917, + "graz": 26918, + "##ruff": 26919, + "handicapped": 26920, + "marlene": 26921, + "tweed": 26922, + "oaxaca": 26923, + "spp": 26924, + "campos": 26925, + "miocene": 26926, + "pri": 26927, + "configured": 26928, + "cooks": 26929, + "pluto": 26930, + "cozy": 26931, + "pornographic": 26932, + "##entes": 26933, + "70th": 26934, + "fairness": 26935, + "glided": 26936, + "jonny": 26937, + "lynne": 26938, + "rounding": 26939, + "sired": 26940, + "##emon": 26941, + "##nist": 26942, + "remade": 26943, + "uncover": 26944, + "##mack": 26945, + "complied": 26946, + "lei": 26947, + "newsweek": 26948, + "##jured": 26949, + "##parts": 26950, + "##enting": 26951, + "##pg": 26952, + "293": 26953, + "finer": 26954, + "guerrillas": 26955, + "athenian": 26956, + "deng": 26957, + "disused": 26958, + "stepmother": 26959, + "accuse": 26960, + "gingerly": 26961, + "seduction": 26962, + "521": 26963, + "confronting": 26964, + "##walker": 26965, + "##going": 26966, + "gora": 26967, + "nostalgia": 26968, + "sabres": 26969, + "virginity": 26970, + "wrenched": 26971, + "##minated": 26972, + "syndication": 26973, + "wielding": 26974, + "eyre": 26975, + "##56": 26976, + "##gnon": 26977, + "##igny": 26978, + "behaved": 26979, + "taxpayer": 26980, + "sweeps": 26981, + "##growth": 26982, + "childless": 26983, + "gallant": 26984, + "##ywood": 26985, + "amplified": 26986, + "geraldine": 26987, + "scrape": 26988, + "##ffi": 26989, + "babylonian": 26990, + "fresco": 26991, + "##rdan": 26992, + "##kney": 26993, + "##position": 26994, + "1718": 26995, + "restricting": 26996, + "tack": 26997, + "fukuoka": 26998, + "osborn": 26999, + "selector": 27000, + "partnering": 27001, + "##dlow": 27002, + "318": 27003, + "gnu": 27004, + "kia": 27005, + "tak": 27006, + "whitley": 27007, + "gables": 27008, + "##54": 27009, + "##mania": 27010, + "mri": 27011, + "softness": 27012, + "immersion": 27013, + "##bots": 27014, + "##evsky": 27015, + "1713": 27016, + "chilling": 27017, + "insignificant": 27018, + "pcs": 27019, + "##uis": 27020, + "elites": 27021, + "lina": 27022, + "purported": 27023, + "supplemental": 27024, + "teaming": 27025, + "##americana": 27026, + "##dding": 27027, + "##inton": 27028, + "proficient": 27029, + "rouen": 27030, + "##nage": 27031, + "##rret": 27032, + "niccolo": 27033, + "selects": 27034, + "##bread": 27035, + "fluffy": 27036, + "1621": 27037, + "gruff": 27038, + "knotted": 27039, + "mukherjee": 27040, + "polgara": 27041, + "thrash": 27042, + "nicholls": 27043, + "secluded": 27044, + "smoothing": 27045, + "thru": 27046, + "corsica": 27047, + "loaf": 27048, + "whitaker": 27049, + "inquiries": 27050, + "##rrier": 27051, + "##kam": 27052, + "indochina": 27053, + "289": 27054, + "marlins": 27055, + "myles": 27056, + "peking": 27057, + "##tea": 27058, + "extracts": 27059, + "pastry": 27060, + "superhuman": 27061, + "connacht": 27062, + "vogel": 27063, + "##ditional": 27064, + "##het": 27065, + "##udged": 27066, + "##lash": 27067, + "gloss": 27068, + "quarries": 27069, + "refit": 27070, + "teaser": 27071, + "##alic": 27072, + "##gaon": 27073, + "20s": 27074, + "materialized": 27075, + "sling": 27076, + "camped": 27077, + "pickering": 27078, + "tung": 27079, + "tracker": 27080, + "pursuant": 27081, + "##cide": 27082, + "cranes": 27083, + "soc": 27084, + "##cini": 27085, + "##typical": 27086, + "##viere": 27087, + "anhalt": 27088, + "overboard": 27089, + "workout": 27090, + "chores": 27091, + "fares": 27092, + "orphaned": 27093, + "stains": 27094, + "##logie": 27095, + "fenton": 27096, + "surpassing": 27097, + "joyah": 27098, + "triggers": 27099, + "##itte": 27100, + "grandmaster": 27101, + "##lass": 27102, + "##lists": 27103, + "clapping": 27104, + "fraudulent": 27105, + "ledger": 27106, + "nagasaki": 27107, + "##cor": 27108, + "##nosis": 27109, + "##tsa": 27110, + "eucalyptus": 27111, + "tun": 27112, + "##icio": 27113, + "##rney": 27114, + "##tara": 27115, + "dax": 27116, + "heroism": 27117, + "ina": 27118, + "wrexham": 27119, + "onboard": 27120, + "unsigned": 27121, + "##dates": 27122, + "moshe": 27123, + "galley": 27124, + "winnie": 27125, + "droplets": 27126, + "exiles": 27127, + "praises": 27128, + "watered": 27129, + "noodles": 27130, + "##aia": 27131, + "fein": 27132, + "adi": 27133, + "leland": 27134, + "multicultural": 27135, + "stink": 27136, + "bingo": 27137, + "comets": 27138, + "erskine": 27139, + "modernized": 27140, + "canned": 27141, + "constraint": 27142, + "domestically": 27143, + "chemotherapy": 27144, + "featherweight": 27145, + "stifled": 27146, + "##mum": 27147, + "darkly": 27148, + "irresistible": 27149, + "refreshing": 27150, + "hasty": 27151, + "isolate": 27152, + "##oys": 27153, + "kitchener": 27154, + "planners": 27155, + "##wehr": 27156, + "cages": 27157, + "yarn": 27158, + "implant": 27159, + "toulon": 27160, + "elects": 27161, + "childbirth": 27162, + "yue": 27163, + "##lind": 27164, + "##lone": 27165, + "cn": 27166, + "rightful": 27167, + "sportsman": 27168, + "junctions": 27169, + "remodeled": 27170, + "specifies": 27171, + "##rgh": 27172, + "291": 27173, + "##oons": 27174, + "complimented": 27175, + "##urgent": 27176, + "lister": 27177, + "ot": 27178, + "##logic": 27179, + "bequeathed": 27180, + "cheekbones": 27181, + "fontana": 27182, + "gabby": 27183, + "##dial": 27184, + "amadeus": 27185, + "corrugated": 27186, + "maverick": 27187, + "resented": 27188, + "triangles": 27189, + "##hered": 27190, + "##usly": 27191, + "nazareth": 27192, + "tyrol": 27193, + "1675": 27194, + "assent": 27195, + "poorer": 27196, + "sectional": 27197, + "aegean": 27198, + "##cous": 27199, + "296": 27200, + "nylon": 27201, + "ghanaian": 27202, + "##egorical": 27203, + "##weig": 27204, + "cushions": 27205, + "forbid": 27206, + "fusiliers": 27207, + "obstruction": 27208, + "somerville": 27209, + "##scia": 27210, + "dime": 27211, + "earrings": 27212, + "elliptical": 27213, + "leyte": 27214, + "oder": 27215, + "polymers": 27216, + "timmy": 27217, + "atm": 27218, + "midtown": 27219, + "piloted": 27220, + "settles": 27221, + "continual": 27222, + "externally": 27223, + "mayfield": 27224, + "##uh": 27225, + "enrichment": 27226, + "henson": 27227, + "keane": 27228, + "persians": 27229, + "1733": 27230, + "benji": 27231, + "braden": 27232, + "pep": 27233, + "324": 27234, + "##efe": 27235, + "contenders": 27236, + "pepsi": 27237, + "valet": 27238, + "##isches": 27239, + "298": 27240, + "##asse": 27241, + "##earing": 27242, + "goofy": 27243, + "stroll": 27244, + "##amen": 27245, + "authoritarian": 27246, + "occurrences": 27247, + "adversary": 27248, + "ahmedabad": 27249, + "tangent": 27250, + "toppled": 27251, + "dorchester": 27252, + "1672": 27253, + "modernism": 27254, + "marxism": 27255, + "islamist": 27256, + "charlemagne": 27257, + "exponential": 27258, + "racks": 27259, + "unicode": 27260, + "brunette": 27261, + "mbc": 27262, + "pic": 27263, + "skirmish": 27264, + "##bund": 27265, + "##lad": 27266, + "##powered": 27267, + "##yst": 27268, + "hoisted": 27269, + "messina": 27270, + "shatter": 27271, + "##ctum": 27272, + "jedi": 27273, + "vantage": 27274, + "##music": 27275, + "##neil": 27276, + "clemens": 27277, + "mahmoud": 27278, + "corrupted": 27279, + "authentication": 27280, + "lowry": 27281, + "nils": 27282, + "##washed": 27283, + "omnibus": 27284, + "wounding": 27285, + "jillian": 27286, + "##itors": 27287, + "##opped": 27288, + "serialized": 27289, + "narcotics": 27290, + "handheld": 27291, + "##arm": 27292, + "##plicity": 27293, + "intersecting": 27294, + "stimulating": 27295, + "##onis": 27296, + "crate": 27297, + "fellowships": 27298, + "hemingway": 27299, + "casinos": 27300, + "climatic": 27301, + "fordham": 27302, + "copeland": 27303, + "drip": 27304, + "beatty": 27305, + "leaflets": 27306, + "robber": 27307, + "brothel": 27308, + "madeira": 27309, + "##hedral": 27310, + "sphinx": 27311, + "ultrasound": 27312, + "##vana": 27313, + "valor": 27314, + "forbade": 27315, + "leonid": 27316, + "villas": 27317, + "##aldo": 27318, + "duane": 27319, + "marquez": 27320, + "##cytes": 27321, + "disadvantaged": 27322, + "forearms": 27323, + "kawasaki": 27324, + "reacts": 27325, + "consular": 27326, + "lax": 27327, + "uncles": 27328, + "uphold": 27329, + "##hopper": 27330, + "concepcion": 27331, + "dorsey": 27332, + "lass": 27333, + "##izan": 27334, + "arching": 27335, + "passageway": 27336, + "1708": 27337, + "researches": 27338, + "tia": 27339, + "internationals": 27340, + "##graphs": 27341, + "##opers": 27342, + "distinguishes": 27343, + "javanese": 27344, + "divert": 27345, + "##uven": 27346, + "plotted": 27347, + "##listic": 27348, + "##rwin": 27349, + "##erik": 27350, + "##tify": 27351, + "affirmative": 27352, + "signifies": 27353, + "validation": 27354, + "##bson": 27355, + "kari": 27356, + "felicity": 27357, + "georgina": 27358, + "zulu": 27359, + "##eros": 27360, + "##rained": 27361, + "##rath": 27362, + "overcoming": 27363, + "##dot": 27364, + "argyll": 27365, + "##rbin": 27366, + "1734": 27367, + "chiba": 27368, + "ratification": 27369, + "windy": 27370, + "earls": 27371, + "parapet": 27372, + "##marks": 27373, + "hunan": 27374, + "pristine": 27375, + "astrid": 27376, + "punta": 27377, + "##gart": 27378, + "brodie": 27379, + "##kota": 27380, + "##oder": 27381, + "malaga": 27382, + "minerva": 27383, + "rouse": 27384, + "##phonic": 27385, + "bellowed": 27386, + "pagoda": 27387, + "portals": 27388, + "reclamation": 27389, + "##gur": 27390, + "##odies": 27391, + "##⁄₄": 27392, + "parentheses": 27393, + "quoting": 27394, + "allergic": 27395, + "palette": 27396, + "showcases": 27397, + "benefactor": 27398, + "heartland": 27399, + "nonlinear": 27400, + "##tness": 27401, + "bladed": 27402, + "cheerfully": 27403, + "scans": 27404, + "##ety": 27405, + "##hone": 27406, + "1666": 27407, + "girlfriends": 27408, + "pedersen": 27409, + "hiram": 27410, + "sous": 27411, + "##liche": 27412, + "##nator": 27413, + "1683": 27414, + "##nery": 27415, + "##orio": 27416, + "##umen": 27417, + "bobo": 27418, + "primaries": 27419, + "smiley": 27420, + "##cb": 27421, + "unearthed": 27422, + "uniformly": 27423, + "fis": 27424, + "metadata": 27425, + "1635": 27426, + "ind": 27427, + "##oted": 27428, + "recoil": 27429, + "##titles": 27430, + "##tura": 27431, + "##ια": 27432, + "406": 27433, + "hilbert": 27434, + "jamestown": 27435, + "mcmillan": 27436, + "tulane": 27437, + "seychelles": 27438, + "##frid": 27439, + "antics": 27440, + "coli": 27441, + "fated": 27442, + "stucco": 27443, + "##grants": 27444, + "1654": 27445, + "bulky": 27446, + "accolades": 27447, + "arrays": 27448, + "caledonian": 27449, + "carnage": 27450, + "optimism": 27451, + "puebla": 27452, + "##tative": 27453, + "##cave": 27454, + "enforcing": 27455, + "rotherham": 27456, + "seo": 27457, + "dunlop": 27458, + "aeronautics": 27459, + "chimed": 27460, + "incline": 27461, + "zoning": 27462, + "archduke": 27463, + "hellenistic": 27464, + "##oses": 27465, + "##sions": 27466, + "candi": 27467, + "thong": 27468, + "##ople": 27469, + "magnate": 27470, + "rustic": 27471, + "##rsk": 27472, + "projective": 27473, + "slant": 27474, + "##offs": 27475, + "danes": 27476, + "hollis": 27477, + "vocalists": 27478, + "##ammed": 27479, + "congenital": 27480, + "contend": 27481, + "gesellschaft": 27482, + "##ocating": 27483, + "##pressive": 27484, + "douglass": 27485, + "quieter": 27486, + "##cm": 27487, + "##kshi": 27488, + "howled": 27489, + "salim": 27490, + "spontaneously": 27491, + "townsville": 27492, + "buena": 27493, + "southport": 27494, + "##bold": 27495, + "kato": 27496, + "1638": 27497, + "faerie": 27498, + "stiffly": 27499, + "##vus": 27500, + "##rled": 27501, + "297": 27502, + "flawless": 27503, + "realising": 27504, + "taboo": 27505, + "##7th": 27506, + "bytes": 27507, + "straightening": 27508, + "356": 27509, + "jena": 27510, + "##hid": 27511, + "##rmin": 27512, + "cartwright": 27513, + "berber": 27514, + "bertram": 27515, + "soloists": 27516, + "411": 27517, + "noses": 27518, + "417": 27519, + "coping": 27520, + "fission": 27521, + "hardin": 27522, + "inca": 27523, + "##cen": 27524, + "1717": 27525, + "mobilized": 27526, + "vhf": 27527, + "##raf": 27528, + "biscuits": 27529, + "curate": 27530, + "##85": 27531, + "##anial": 27532, + "331": 27533, + "gaunt": 27534, + "neighbourhoods": 27535, + "1540": 27536, + "##abas": 27537, + "blanca": 27538, + "bypassed": 27539, + "sockets": 27540, + "behold": 27541, + "coincidentally": 27542, + "##bane": 27543, + "nara": 27544, + "shave": 27545, + "splinter": 27546, + "terrific": 27547, + "##arion": 27548, + "##erian": 27549, + "commonplace": 27550, + "juris": 27551, + "redwood": 27552, + "waistband": 27553, + "boxed": 27554, + "caitlin": 27555, + "fingerprints": 27556, + "jennie": 27557, + "naturalized": 27558, + "##ired": 27559, + "balfour": 27560, + "craters": 27561, + "jody": 27562, + "bungalow": 27563, + "hugely": 27564, + "quilt": 27565, + "glitter": 27566, + "pigeons": 27567, + "undertaker": 27568, + "bulging": 27569, + "constrained": 27570, + "goo": 27571, + "##sil": 27572, + "##akh": 27573, + "assimilation": 27574, + "reworked": 27575, + "##person": 27576, + "persuasion": 27577, + "##pants": 27578, + "felicia": 27579, + "##cliff": 27580, + "##ulent": 27581, + "1732": 27582, + "explodes": 27583, + "##dun": 27584, + "##inium": 27585, + "##zic": 27586, + "lyman": 27587, + "vulture": 27588, + "hog": 27589, + "overlook": 27590, + "begs": 27591, + "northwards": 27592, + "ow": 27593, + "spoil": 27594, + "##urer": 27595, + "fatima": 27596, + "favorably": 27597, + "accumulate": 27598, + "sargent": 27599, + "sorority": 27600, + "corresponded": 27601, + "dispersal": 27602, + "kochi": 27603, + "toned": 27604, + "##imi": 27605, + "##lita": 27606, + "internacional": 27607, + "newfound": 27608, + "##agger": 27609, + "##lynn": 27610, + "##rigue": 27611, + "booths": 27612, + "peanuts": 27613, + "##eborg": 27614, + "medicare": 27615, + "muriel": 27616, + "nur": 27617, + "##uram": 27618, + "crates": 27619, + "millennia": 27620, + "pajamas": 27621, + "worsened": 27622, + "##breakers": 27623, + "jimi": 27624, + "vanuatu": 27625, + "yawned": 27626, + "##udeau": 27627, + "carousel": 27628, + "##hony": 27629, + "hurdle": 27630, + "##ccus": 27631, + "##mounted": 27632, + "##pod": 27633, + "rv": 27634, + "##eche": 27635, + "airship": 27636, + "ambiguity": 27637, + "compulsion": 27638, + "recapture": 27639, + "##claiming": 27640, + "arthritis": 27641, + "##osomal": 27642, + "1667": 27643, + "asserting": 27644, + "ngc": 27645, + "sniffing": 27646, + "dade": 27647, + "discontent": 27648, + "glendale": 27649, + "ported": 27650, + "##amina": 27651, + "defamation": 27652, + "rammed": 27653, + "##scent": 27654, + "fling": 27655, + "livingstone": 27656, + "##fleet": 27657, + "875": 27658, + "##ppy": 27659, + "apocalyptic": 27660, + "comrade": 27661, + "lcd": 27662, + "##lowe": 27663, + "cessna": 27664, + "eine": 27665, + "persecuted": 27666, + "subsistence": 27667, + "demi": 27668, + "hoop": 27669, + "reliefs": 27670, + "710": 27671, + "coptic": 27672, + "progressing": 27673, + "stemmed": 27674, + "perpetrators": 27675, + "1665": 27676, + "priestess": 27677, + "##nio": 27678, + "dobson": 27679, + "ebony": 27680, + "rooster": 27681, + "itf": 27682, + "tortricidae": 27683, + "##bbon": 27684, + "##jian": 27685, + "cleanup": 27686, + "##jean": 27687, + "##øy": 27688, + "1721": 27689, + "eighties": 27690, + "taxonomic": 27691, + "holiness": 27692, + "##hearted": 27693, + "##spar": 27694, + "antilles": 27695, + "showcasing": 27696, + "stabilized": 27697, + "##nb": 27698, + "gia": 27699, + "mascara": 27700, + "michelangelo": 27701, + "dawned": 27702, + "##uria": 27703, + "##vinsky": 27704, + "extinguished": 27705, + "fitz": 27706, + "grotesque": 27707, + "£100": 27708, + "##fera": 27709, + "##loid": 27710, + "##mous": 27711, + "barges": 27712, + "neue": 27713, + "throbbed": 27714, + "cipher": 27715, + "johnnie": 27716, + "##a1": 27717, + "##mpt": 27718, + "outburst": 27719, + "##swick": 27720, + "spearheaded": 27721, + "administrations": 27722, + "c1": 27723, + "heartbreak": 27724, + "pixels": 27725, + "pleasantly": 27726, + "##enay": 27727, + "lombardy": 27728, + "plush": 27729, + "##nsed": 27730, + "bobbie": 27731, + "##hly": 27732, + "reapers": 27733, + "tremor": 27734, + "xiang": 27735, + "minogue": 27736, + "substantive": 27737, + "hitch": 27738, + "barak": 27739, + "##wyl": 27740, + "kwan": 27741, + "##encia": 27742, + "910": 27743, + "obscene": 27744, + "elegance": 27745, + "indus": 27746, + "surfer": 27747, + "bribery": 27748, + "conserve": 27749, + "##hyllum": 27750, + "##masters": 27751, + "horatio": 27752, + "##fat": 27753, + "apes": 27754, + "rebound": 27755, + "psychotic": 27756, + "##pour": 27757, + "iteration": 27758, + "##mium": 27759, + "##vani": 27760, + "botanic": 27761, + "horribly": 27762, + "antiques": 27763, + "dispose": 27764, + "paxton": 27765, + "##hli": 27766, + "##wg": 27767, + "timeless": 27768, + "1704": 27769, + "disregard": 27770, + "engraver": 27771, + "hounds": 27772, + "##bau": 27773, + "##version": 27774, + "looted": 27775, + "uno": 27776, + "facilitates": 27777, + "groans": 27778, + "masjid": 27779, + "rutland": 27780, + "antibody": 27781, + "disqualification": 27782, + "decatur": 27783, + "footballers": 27784, + "quake": 27785, + "slacks": 27786, + "48th": 27787, + "rein": 27788, + "scribe": 27789, + "stabilize": 27790, + "commits": 27791, + "exemplary": 27792, + "tho": 27793, + "##hort": 27794, + "##chison": 27795, + "pantry": 27796, + "traversed": 27797, + "##hiti": 27798, + "disrepair": 27799, + "identifiable": 27800, + "vibrated": 27801, + "baccalaureate": 27802, + "##nnis": 27803, + "csa": 27804, + "interviewing": 27805, + "##iensis": 27806, + "##raße": 27807, + "greaves": 27808, + "wealthiest": 27809, + "343": 27810, + "classed": 27811, + "jogged": 27812, + "£5": 27813, + "##58": 27814, + "##atal": 27815, + "illuminating": 27816, + "knicks": 27817, + "respecting": 27818, + "##uno": 27819, + "scrubbed": 27820, + "##iji": 27821, + "##dles": 27822, + "kruger": 27823, + "moods": 27824, + "growls": 27825, + "raider": 27826, + "silvia": 27827, + "chefs": 27828, + "kam": 27829, + "vr": 27830, + "cree": 27831, + "percival": 27832, + "##terol": 27833, + "gunter": 27834, + "counterattack": 27835, + "defiant": 27836, + "henan": 27837, + "ze": 27838, + "##rasia": 27839, + "##riety": 27840, + "equivalence": 27841, + "submissions": 27842, + "##fra": 27843, + "##thor": 27844, + "bautista": 27845, + "mechanically": 27846, + "##heater": 27847, + "cornice": 27848, + "herbal": 27849, + "templar": 27850, + "##mering": 27851, + "outputs": 27852, + "ruining": 27853, + "ligand": 27854, + "renumbered": 27855, + "extravagant": 27856, + "mika": 27857, + "blockbuster": 27858, + "eta": 27859, + "insurrection": 27860, + "##ilia": 27861, + "darkening": 27862, + "ferocious": 27863, + "pianos": 27864, + "strife": 27865, + "kinship": 27866, + "##aer": 27867, + "melee": 27868, + "##anor": 27869, + "##iste": 27870, + "##may": 27871, + "##oue": 27872, + "decidedly": 27873, + "weep": 27874, + "##jad": 27875, + "##missive": 27876, + "##ppel": 27877, + "354": 27878, + "puget": 27879, + "unease": 27880, + "##gnant": 27881, + "1629": 27882, + "hammering": 27883, + "kassel": 27884, + "ob": 27885, + "wessex": 27886, + "##lga": 27887, + "bromwich": 27888, + "egan": 27889, + "paranoia": 27890, + "utilization": 27891, + "##atable": 27892, + "##idad": 27893, + "contradictory": 27894, + "provoke": 27895, + "##ols": 27896, + "##ouring": 27897, + "##tangled": 27898, + "knesset": 27899, + "##very": 27900, + "##lette": 27901, + "plumbing": 27902, + "##sden": 27903, + "##¹": 27904, + "greensboro": 27905, + "occult": 27906, + "sniff": 27907, + "338": 27908, + "zev": 27909, + "beaming": 27910, + "gamer": 27911, + "haggard": 27912, + "mahal": 27913, + "##olt": 27914, + "##pins": 27915, + "mendes": 27916, + "utmost": 27917, + "briefing": 27918, + "gunnery": 27919, + "##gut": 27920, + "##pher": 27921, + "##zh": 27922, + "##rok": 27923, + "1679": 27924, + "khalifa": 27925, + "sonya": 27926, + "##boot": 27927, + "principals": 27928, + "urbana": 27929, + "wiring": 27930, + "##liffe": 27931, + "##minating": 27932, + "##rrado": 27933, + "dahl": 27934, + "nyu": 27935, + "skepticism": 27936, + "np": 27937, + "townspeople": 27938, + "ithaca": 27939, + "lobster": 27940, + "somethin": 27941, + "##fur": 27942, + "##arina": 27943, + "##−1": 27944, + "freighter": 27945, + "zimmerman": 27946, + "biceps": 27947, + "contractual": 27948, + "##herton": 27949, + "amend": 27950, + "hurrying": 27951, + "subconscious": 27952, + "##anal": 27953, + "336": 27954, + "meng": 27955, + "clermont": 27956, + "spawning": 27957, + "##eia": 27958, + "##lub": 27959, + "dignitaries": 27960, + "impetus": 27961, + "snacks": 27962, + "spotting": 27963, + "twigs": 27964, + "##bilis": 27965, + "##cz": 27966, + "##ouk": 27967, + "libertadores": 27968, + "nic": 27969, + "skylar": 27970, + "##aina": 27971, + "##firm": 27972, + "gustave": 27973, + "asean": 27974, + "##anum": 27975, + "dieter": 27976, + "legislatures": 27977, + "flirt": 27978, + "bromley": 27979, + "trolls": 27980, + "umar": 27981, + "##bbies": 27982, + "##tyle": 27983, + "blah": 27984, + "parc": 27985, + "bridgeport": 27986, + "crank": 27987, + "negligence": 27988, + "##nction": 27989, + "46th": 27990, + "constantin": 27991, + "molded": 27992, + "bandages": 27993, + "seriousness": 27994, + "00pm": 27995, + "siegel": 27996, + "carpets": 27997, + "compartments": 27998, + "upbeat": 27999, + "statehood": 28000, + "##dner": 28001, + "##edging": 28002, + "marko": 28003, + "730": 28004, + "platt": 28005, + "##hane": 28006, + "paving": 28007, + "##iy": 28008, + "1738": 28009, + "abbess": 28010, + "impatience": 28011, + "limousine": 28012, + "nbl": 28013, + "##talk": 28014, + "441": 28015, + "lucille": 28016, + "mojo": 28017, + "nightfall": 28018, + "robbers": 28019, + "##nais": 28020, + "karel": 28021, + "brisk": 28022, + "calves": 28023, + "replicate": 28024, + "ascribed": 28025, + "telescopes": 28026, + "##olf": 28027, + "intimidated": 28028, + "##reen": 28029, + "ballast": 28030, + "specialization": 28031, + "##sit": 28032, + "aerodynamic": 28033, + "caliphate": 28034, + "rainer": 28035, + "visionary": 28036, + "##arded": 28037, + "epsilon": 28038, + "##aday": 28039, + "##onte": 28040, + "aggregation": 28041, + "auditory": 28042, + "boosted": 28043, + "reunification": 28044, + "kathmandu": 28045, + "loco": 28046, + "robyn": 28047, + "402": 28048, + "acknowledges": 28049, + "appointing": 28050, + "humanoid": 28051, + "newell": 28052, + "redeveloped": 28053, + "restraints": 28054, + "##tained": 28055, + "barbarians": 28056, + "chopper": 28057, + "1609": 28058, + "italiana": 28059, + "##lez": 28060, + "##lho": 28061, + "investigates": 28062, + "wrestlemania": 28063, + "##anies": 28064, + "##bib": 28065, + "690": 28066, + "##falls": 28067, + "creaked": 28068, + "dragoons": 28069, + "gravely": 28070, + "minions": 28071, + "stupidity": 28072, + "volley": 28073, + "##harat": 28074, + "##week": 28075, + "musik": 28076, + "##eries": 28077, + "##uously": 28078, + "fungal": 28079, + "massimo": 28080, + "semantics": 28081, + "malvern": 28082, + "##ahl": 28083, + "##pee": 28084, + "discourage": 28085, + "embryo": 28086, + "imperialism": 28087, + "1910s": 28088, + "profoundly": 28089, + "##ddled": 28090, + "jiangsu": 28091, + "sparkled": 28092, + "stat": 28093, + "##holz": 28094, + "sweatshirt": 28095, + "tobin": 28096, + "##iction": 28097, + "sneered": 28098, + "##cheon": 28099, + "##oit": 28100, + "brit": 28101, + "causal": 28102, + "smyth": 28103, + "##neuve": 28104, + "diffuse": 28105, + "perrin": 28106, + "silvio": 28107, + "##ipes": 28108, + "##recht": 28109, + "detonated": 28110, + "iqbal": 28111, + "selma": 28112, + "##nism": 28113, + "##zumi": 28114, + "roasted": 28115, + "##riders": 28116, + "tay": 28117, + "##ados": 28118, + "##mament": 28119, + "##mut": 28120, + "##rud": 28121, + "840": 28122, + "completes": 28123, + "nipples": 28124, + "cfa": 28125, + "flavour": 28126, + "hirsch": 28127, + "##laus": 28128, + "calderon": 28129, + "sneakers": 28130, + "moravian": 28131, + "##ksha": 28132, + "1622": 28133, + "rq": 28134, + "294": 28135, + "##imeters": 28136, + "bodo": 28137, + "##isance": 28138, + "##pre": 28139, + "##ronia": 28140, + "anatomical": 28141, + "excerpt": 28142, + "##lke": 28143, + "dh": 28144, + "kunst": 28145, + "##tablished": 28146, + "##scoe": 28147, + "biomass": 28148, + "panted": 28149, + "unharmed": 28150, + "gael": 28151, + "housemates": 28152, + "montpellier": 28153, + "##59": 28154, + "coa": 28155, + "rodents": 28156, + "tonic": 28157, + "hickory": 28158, + "singleton": 28159, + "##taro": 28160, + "451": 28161, + "1719": 28162, + "aldo": 28163, + "breaststroke": 28164, + "dempsey": 28165, + "och": 28166, + "rocco": 28167, + "##cuit": 28168, + "merton": 28169, + "dissemination": 28170, + "midsummer": 28171, + "serials": 28172, + "##idi": 28173, + "haji": 28174, + "polynomials": 28175, + "##rdon": 28176, + "gs": 28177, + "enoch": 28178, + "prematurely": 28179, + "shutter": 28180, + "taunton": 28181, + "£3": 28182, + "##grating": 28183, + "##inates": 28184, + "archangel": 28185, + "harassed": 28186, + "##asco": 28187, + "326": 28188, + "archway": 28189, + "dazzling": 28190, + "##ecin": 28191, + "1736": 28192, + "sumo": 28193, + "wat": 28194, + "##kovich": 28195, + "1086": 28196, + "honneur": 28197, + "##ently": 28198, + "##nostic": 28199, + "##ttal": 28200, + "##idon": 28201, + "1605": 28202, + "403": 28203, + "1716": 28204, + "blogger": 28205, + "rents": 28206, + "##gnan": 28207, + "hires": 28208, + "##ikh": 28209, + "##dant": 28210, + "howie": 28211, + "##rons": 28212, + "handler": 28213, + "retracted": 28214, + "shocks": 28215, + "1632": 28216, + "arun": 28217, + "duluth": 28218, + "kepler": 28219, + "trumpeter": 28220, + "##lary": 28221, + "peeking": 28222, + "seasoned": 28223, + "trooper": 28224, + "##mara": 28225, + "laszlo": 28226, + "##iciencies": 28227, + "##rti": 28228, + "heterosexual": 28229, + "##inatory": 28230, + "##ssion": 28231, + "indira": 28232, + "jogging": 28233, + "##inga": 28234, + "##lism": 28235, + "beit": 28236, + "dissatisfaction": 28237, + "malice": 28238, + "##ately": 28239, + "nedra": 28240, + "peeling": 28241, + "##rgeon": 28242, + "47th": 28243, + "stadiums": 28244, + "475": 28245, + "vertigo": 28246, + "##ains": 28247, + "iced": 28248, + "restroom": 28249, + "##plify": 28250, + "##tub": 28251, + "illustrating": 28252, + "pear": 28253, + "##chner": 28254, + "##sibility": 28255, + "inorganic": 28256, + "rappers": 28257, + "receipts": 28258, + "watery": 28259, + "##kura": 28260, + "lucinda": 28261, + "##oulos": 28262, + "reintroduced": 28263, + "##8th": 28264, + "##tched": 28265, + "gracefully": 28266, + "saxons": 28267, + "nutritional": 28268, + "wastewater": 28269, + "rained": 28270, + "favourites": 28271, + "bedrock": 28272, + "fisted": 28273, + "hallways": 28274, + "likeness": 28275, + "upscale": 28276, + "##lateral": 28277, + "1580": 28278, + "blinds": 28279, + "prequel": 28280, + "##pps": 28281, + "##tama": 28282, + "deter": 28283, + "humiliating": 28284, + "restraining": 28285, + "tn": 28286, + "vents": 28287, + "1659": 28288, + "laundering": 28289, + "recess": 28290, + "rosary": 28291, + "tractors": 28292, + "coulter": 28293, + "federer": 28294, + "##ifiers": 28295, + "##plin": 28296, + "persistence": 28297, + "##quitable": 28298, + "geschichte": 28299, + "pendulum": 28300, + "quakers": 28301, + "##beam": 28302, + "bassett": 28303, + "pictorial": 28304, + "buffet": 28305, + "koln": 28306, + "##sitor": 28307, + "drills": 28308, + "reciprocal": 28309, + "shooters": 28310, + "##57": 28311, + "##cton": 28312, + "##tees": 28313, + "converge": 28314, + "pip": 28315, + "dmitri": 28316, + "donnelly": 28317, + "yamamoto": 28318, + "aqua": 28319, + "azores": 28320, + "demographics": 28321, + "hypnotic": 28322, + "spitfire": 28323, + "suspend": 28324, + "wryly": 28325, + "roderick": 28326, + "##rran": 28327, + "sebastien": 28328, + "##asurable": 28329, + "mavericks": 28330, + "##fles": 28331, + "##200": 28332, + "himalayan": 28333, + "prodigy": 28334, + "##iance": 28335, + "transvaal": 28336, + "demonstrators": 28337, + "handcuffs": 28338, + "dodged": 28339, + "mcnamara": 28340, + "sublime": 28341, + "1726": 28342, + "crazed": 28343, + "##efined": 28344, + "##till": 28345, + "ivo": 28346, + "pondered": 28347, + "reconciled": 28348, + "shrill": 28349, + "sava": 28350, + "##duk": 28351, + "bal": 28352, + "cad": 28353, + "heresy": 28354, + "jaipur": 28355, + "goran": 28356, + "##nished": 28357, + "341": 28358, + "lux": 28359, + "shelly": 28360, + "whitehall": 28361, + "##hre": 28362, + "israelis": 28363, + "peacekeeping": 28364, + "##wled": 28365, + "1703": 28366, + "demetrius": 28367, + "ousted": 28368, + "##arians": 28369, + "##zos": 28370, + "beale": 28371, + "anwar": 28372, + "backstroke": 28373, + "raged": 28374, + "shrinking": 28375, + "cremated": 28376, + "##yck": 28377, + "benign": 28378, + "towing": 28379, + "wadi": 28380, + "darmstadt": 28381, + "landfill": 28382, + "parana": 28383, + "soothe": 28384, + "colleen": 28385, + "sidewalks": 28386, + "mayfair": 28387, + "tumble": 28388, + "hepatitis": 28389, + "ferrer": 28390, + "superstructure": 28391, + "##gingly": 28392, + "##urse": 28393, + "##wee": 28394, + "anthropological": 28395, + "translators": 28396, + "##mies": 28397, + "closeness": 28398, + "hooves": 28399, + "##pw": 28400, + "mondays": 28401, + "##roll": 28402, + "##vita": 28403, + "landscaping": 28404, + "##urized": 28405, + "purification": 28406, + "sock": 28407, + "thorns": 28408, + "thwarted": 28409, + "jalan": 28410, + "tiberius": 28411, + "##taka": 28412, + "saline": 28413, + "##rito": 28414, + "confidently": 28415, + "khyber": 28416, + "sculptors": 28417, + "##ij": 28418, + "brahms": 28419, + "hammersmith": 28420, + "inspectors": 28421, + "battista": 28422, + "fivb": 28423, + "fragmentation": 28424, + "hackney": 28425, + "##uls": 28426, + "arresting": 28427, + "exercising": 28428, + "antoinette": 28429, + "bedfordshire": 28430, + "##zily": 28431, + "dyed": 28432, + "##hema": 28433, + "1656": 28434, + "racetrack": 28435, + "variability": 28436, + "##tique": 28437, + "1655": 28438, + "austrians": 28439, + "deteriorating": 28440, + "madman": 28441, + "theorists": 28442, + "aix": 28443, + "lehman": 28444, + "weathered": 28445, + "1731": 28446, + "decreed": 28447, + "eruptions": 28448, + "1729": 28449, + "flaw": 28450, + "quinlan": 28451, + "sorbonne": 28452, + "flutes": 28453, + "nunez": 28454, + "1711": 28455, + "adored": 28456, + "downwards": 28457, + "fable": 28458, + "rasped": 28459, + "1712": 28460, + "moritz": 28461, + "mouthful": 28462, + "renegade": 28463, + "shivers": 28464, + "stunts": 28465, + "dysfunction": 28466, + "restrain": 28467, + "translit": 28468, + "327": 28469, + "pancakes": 28470, + "##avio": 28471, + "##cision": 28472, + "##tray": 28473, + "351": 28474, + "vial": 28475, + "##lden": 28476, + "bain": 28477, + "##maid": 28478, + "##oxide": 28479, + "chihuahua": 28480, + "malacca": 28481, + "vimes": 28482, + "##rba": 28483, + "##rnier": 28484, + "1664": 28485, + "donnie": 28486, + "plaques": 28487, + "##ually": 28488, + "337": 28489, + "bangs": 28490, + "floppy": 28491, + "huntsville": 28492, + "loretta": 28493, + "nikolay": 28494, + "##otte": 28495, + "eater": 28496, + "handgun": 28497, + "ubiquitous": 28498, + "##hett": 28499, + "eras": 28500, + "zodiac": 28501, + "1634": 28502, + "##omorphic": 28503, + "1820s": 28504, + "##zog": 28505, + "cochran": 28506, + "##bula": 28507, + "##lithic": 28508, + "warring": 28509, + "##rada": 28510, + "dalai": 28511, + "excused": 28512, + "blazers": 28513, + "mcconnell": 28514, + "reeling": 28515, + "bot": 28516, + "este": 28517, + "##abi": 28518, + "geese": 28519, + "hoax": 28520, + "taxon": 28521, + "##bla": 28522, + "guitarists": 28523, + "##icon": 28524, + "condemning": 28525, + "hunts": 28526, + "inversion": 28527, + "moffat": 28528, + "taekwondo": 28529, + "##lvis": 28530, + "1624": 28531, + "stammered": 28532, + "##rest": 28533, + "##rzy": 28534, + "sousa": 28535, + "fundraiser": 28536, + "marylebone": 28537, + "navigable": 28538, + "uptown": 28539, + "cabbage": 28540, + "daniela": 28541, + "salman": 28542, + "shitty": 28543, + "whimper": 28544, + "##kian": 28545, + "##utive": 28546, + "programmers": 28547, + "protections": 28548, + "rm": 28549, + "##rmi": 28550, + "##rued": 28551, + "forceful": 28552, + "##enes": 28553, + "fuss": 28554, + "##tao": 28555, + "##wash": 28556, + "brat": 28557, + "oppressive": 28558, + "reykjavik": 28559, + "spartak": 28560, + "ticking": 28561, + "##inkles": 28562, + "##kiewicz": 28563, + "adolph": 28564, + "horst": 28565, + "maui": 28566, + "protege": 28567, + "straighten": 28568, + "cpc": 28569, + "landau": 28570, + "concourse": 28571, + "clements": 28572, + "resultant": 28573, + "##ando": 28574, + "imaginative": 28575, + "joo": 28576, + "reactivated": 28577, + "##rem": 28578, + "##ffled": 28579, + "##uising": 28580, + "consultative": 28581, + "##guide": 28582, + "flop": 28583, + "kaitlyn": 28584, + "mergers": 28585, + "parenting": 28586, + "somber": 28587, + "##vron": 28588, + "supervise": 28589, + "vidhan": 28590, + "##imum": 28591, + "courtship": 28592, + "exemplified": 28593, + "harmonies": 28594, + "medallist": 28595, + "refining": 28596, + "##rrow": 28597, + "##ка": 28598, + "amara": 28599, + "##hum": 28600, + "780": 28601, + "goalscorer": 28602, + "sited": 28603, + "overshadowed": 28604, + "rohan": 28605, + "displeasure": 28606, + "secretive": 28607, + "multiplied": 28608, + "osman": 28609, + "##orth": 28610, + "engravings": 28611, + "padre": 28612, + "##kali": 28613, + "##veda": 28614, + "miniatures": 28615, + "mis": 28616, + "##yala": 28617, + "clap": 28618, + "pali": 28619, + "rook": 28620, + "##cana": 28621, + "1692": 28622, + "57th": 28623, + "antennae": 28624, + "astro": 28625, + "oskar": 28626, + "1628": 28627, + "bulldog": 28628, + "crotch": 28629, + "hackett": 28630, + "yucatan": 28631, + "##sure": 28632, + "amplifiers": 28633, + "brno": 28634, + "ferrara": 28635, + "migrating": 28636, + "##gree": 28637, + "thanking": 28638, + "turing": 28639, + "##eza": 28640, + "mccann": 28641, + "ting": 28642, + "andersson": 28643, + "onslaught": 28644, + "gaines": 28645, + "ganga": 28646, + "incense": 28647, + "standardization": 28648, + "##mation": 28649, + "sentai": 28650, + "scuba": 28651, + "stuffing": 28652, + "turquoise": 28653, + "waivers": 28654, + "alloys": 28655, + "##vitt": 28656, + "regaining": 28657, + "vaults": 28658, + "##clops": 28659, + "##gizing": 28660, + "digger": 28661, + "furry": 28662, + "memorabilia": 28663, + "probing": 28664, + "##iad": 28665, + "payton": 28666, + "rec": 28667, + "deutschland": 28668, + "filippo": 28669, + "opaque": 28670, + "seamen": 28671, + "zenith": 28672, + "afrikaans": 28673, + "##filtration": 28674, + "disciplined": 28675, + "inspirational": 28676, + "##merie": 28677, + "banco": 28678, + "confuse": 28679, + "grafton": 28680, + "tod": 28681, + "##dgets": 28682, + "championed": 28683, + "simi": 28684, + "anomaly": 28685, + "biplane": 28686, + "##ceptive": 28687, + "electrode": 28688, + "##para": 28689, + "1697": 28690, + "cleavage": 28691, + "crossbow": 28692, + "swirl": 28693, + "informant": 28694, + "##lars": 28695, + "##osta": 28696, + "afi": 28697, + "bonfire": 28698, + "spec": 28699, + "##oux": 28700, + "lakeside": 28701, + "slump": 28702, + "##culus": 28703, + "##lais": 28704, + "##qvist": 28705, + "##rrigan": 28706, + "1016": 28707, + "facades": 28708, + "borg": 28709, + "inwardly": 28710, + "cervical": 28711, + "xl": 28712, + "pointedly": 28713, + "050": 28714, + "stabilization": 28715, + "##odon": 28716, + "chests": 28717, + "1699": 28718, + "hacked": 28719, + "ctv": 28720, + "orthogonal": 28721, + "suzy": 28722, + "##lastic": 28723, + "gaulle": 28724, + "jacobite": 28725, + "rearview": 28726, + "##cam": 28727, + "##erted": 28728, + "ashby": 28729, + "##drik": 28730, + "##igate": 28731, + "##mise": 28732, + "##zbek": 28733, + "affectionately": 28734, + "canine": 28735, + "disperse": 28736, + "latham": 28737, + "##istles": 28738, + "##ivar": 28739, + "spielberg": 28740, + "##orin": 28741, + "##idium": 28742, + "ezekiel": 28743, + "cid": 28744, + "##sg": 28745, + "durga": 28746, + "middletown": 28747, + "##cina": 28748, + "customized": 28749, + "frontiers": 28750, + "harden": 28751, + "##etano": 28752, + "##zzy": 28753, + "1604": 28754, + "bolsheviks": 28755, + "##66": 28756, + "coloration": 28757, + "yoko": 28758, + "##bedo": 28759, + "briefs": 28760, + "slabs": 28761, + "debra": 28762, + "liquidation": 28763, + "plumage": 28764, + "##oin": 28765, + "blossoms": 28766, + "dementia": 28767, + "subsidy": 28768, + "1611": 28769, + "proctor": 28770, + "relational": 28771, + "jerseys": 28772, + "parochial": 28773, + "ter": 28774, + "##ici": 28775, + "esa": 28776, + "peshawar": 28777, + "cavalier": 28778, + "loren": 28779, + "cpi": 28780, + "idiots": 28781, + "shamrock": 28782, + "1646": 28783, + "dutton": 28784, + "malabar": 28785, + "mustache": 28786, + "##endez": 28787, + "##ocytes": 28788, + "referencing": 28789, + "terminates": 28790, + "marche": 28791, + "yarmouth": 28792, + "##sop": 28793, + "acton": 28794, + "mated": 28795, + "seton": 28796, + "subtly": 28797, + "baptised": 28798, + "beige": 28799, + "extremes": 28800, + "jolted": 28801, + "kristina": 28802, + "telecast": 28803, + "##actic": 28804, + "safeguard": 28805, + "waldo": 28806, + "##baldi": 28807, + "##bular": 28808, + "endeavors": 28809, + "sloppy": 28810, + "subterranean": 28811, + "##ensburg": 28812, + "##itung": 28813, + "delicately": 28814, + "pigment": 28815, + "tq": 28816, + "##scu": 28817, + "1626": 28818, + "##ound": 28819, + "collisions": 28820, + "coveted": 28821, + "herds": 28822, + "##personal": 28823, + "##meister": 28824, + "##nberger": 28825, + "chopra": 28826, + "##ricting": 28827, + "abnormalities": 28828, + "defective": 28829, + "galician": 28830, + "lucie": 28831, + "##dilly": 28832, + "alligator": 28833, + "likened": 28834, + "##genase": 28835, + "burundi": 28836, + "clears": 28837, + "complexion": 28838, + "derelict": 28839, + "deafening": 28840, + "diablo": 28841, + "fingered": 28842, + "champaign": 28843, + "dogg": 28844, + "enlist": 28845, + "isotope": 28846, + "labeling": 28847, + "mrna": 28848, + "##erre": 28849, + "brilliance": 28850, + "marvelous": 28851, + "##ayo": 28852, + "1652": 28853, + "crawley": 28854, + "ether": 28855, + "footed": 28856, + "dwellers": 28857, + "deserts": 28858, + "hamish": 28859, + "rubs": 28860, + "warlock": 28861, + "skimmed": 28862, + "##lizer": 28863, + "870": 28864, + "buick": 28865, + "embark": 28866, + "heraldic": 28867, + "irregularities": 28868, + "##ajan": 28869, + "kiara": 28870, + "##kulam": 28871, + "##ieg": 28872, + "antigen": 28873, + "kowalski": 28874, + "##lge": 28875, + "oakley": 28876, + "visitation": 28877, + "##mbit": 28878, + "vt": 28879, + "##suit": 28880, + "1570": 28881, + "murderers": 28882, + "##miento": 28883, + "##rites": 28884, + "chimneys": 28885, + "##sling": 28886, + "condemn": 28887, + "custer": 28888, + "exchequer": 28889, + "havre": 28890, + "##ghi": 28891, + "fluctuations": 28892, + "##rations": 28893, + "dfb": 28894, + "hendricks": 28895, + "vaccines": 28896, + "##tarian": 28897, + "nietzsche": 28898, + "biking": 28899, + "juicy": 28900, + "##duced": 28901, + "brooding": 28902, + "scrolling": 28903, + "selangor": 28904, + "##ragan": 28905, + "352": 28906, + "annum": 28907, + "boomed": 28908, + "seminole": 28909, + "sugarcane": 28910, + "##dna": 28911, + "departmental": 28912, + "dismissing": 28913, + "innsbruck": 28914, + "arteries": 28915, + "ashok": 28916, + "batavia": 28917, + "daze": 28918, + "kun": 28919, + "overtook": 28920, + "##rga": 28921, + "##tlan": 28922, + "beheaded": 28923, + "gaddafi": 28924, + "holm": 28925, + "electronically": 28926, + "faulty": 28927, + "galilee": 28928, + "fractures": 28929, + "kobayashi": 28930, + "##lized": 28931, + "gunmen": 28932, + "magma": 28933, + "aramaic": 28934, + "mala": 28935, + "eastenders": 28936, + "inference": 28937, + "messengers": 28938, + "bf": 28939, + "##qu": 28940, + "407": 28941, + "bathrooms": 28942, + "##vere": 28943, + "1658": 28944, + "flashbacks": 28945, + "ideally": 28946, + "misunderstood": 28947, + "##jali": 28948, + "##weather": 28949, + "mendez": 28950, + "##grounds": 28951, + "505": 28952, + "uncanny": 28953, + "##iii": 28954, + "1709": 28955, + "friendships": 28956, + "##nbc": 28957, + "sacrament": 28958, + "accommodated": 28959, + "reiterated": 28960, + "logistical": 28961, + "pebbles": 28962, + "thumped": 28963, + "##escence": 28964, + "administering": 28965, + "decrees": 28966, + "drafts": 28967, + "##flight": 28968, + "##cased": 28969, + "##tula": 28970, + "futuristic": 28971, + "picket": 28972, + "intimidation": 28973, + "winthrop": 28974, + "##fahan": 28975, + "interfered": 28976, + "339": 28977, + "afar": 28978, + "francoise": 28979, + "morally": 28980, + "uta": 28981, + "cochin": 28982, + "croft": 28983, + "dwarfs": 28984, + "##bruck": 28985, + "##dents": 28986, + "##nami": 28987, + "biker": 28988, + "##hner": 28989, + "##meral": 28990, + "nano": 28991, + "##isen": 28992, + "##ometric": 28993, + "##pres": 28994, + "##ан": 28995, + "brightened": 28996, + "meek": 28997, + "parcels": 28998, + "securely": 28999, + "gunners": 29000, + "##jhl": 29001, + "##zko": 29002, + "agile": 29003, + "hysteria": 29004, + "##lten": 29005, + "##rcus": 29006, + "bukit": 29007, + "champs": 29008, + "chevy": 29009, + "cuckoo": 29010, + "leith": 29011, + "sadler": 29012, + "theologians": 29013, + "welded": 29014, + "##section": 29015, + "1663": 29016, + "jj": 29017, + "plurality": 29018, + "xander": 29019, + "##rooms": 29020, + "##formed": 29021, + "shredded": 29022, + "temps": 29023, + "intimately": 29024, + "pau": 29025, + "tormented": 29026, + "##lok": 29027, + "##stellar": 29028, + "1618": 29029, + "charred": 29030, + "ems": 29031, + "essen": 29032, + "##mmel": 29033, + "alarms": 29034, + "spraying": 29035, + "ascot": 29036, + "blooms": 29037, + "twinkle": 29038, + "##abia": 29039, + "##apes": 29040, + "internment": 29041, + "obsidian": 29042, + "##chaft": 29043, + "snoop": 29044, + "##dav": 29045, + "##ooping": 29046, + "malibu": 29047, + "##tension": 29048, + "quiver": 29049, + "##itia": 29050, + "hays": 29051, + "mcintosh": 29052, + "travers": 29053, + "walsall": 29054, + "##ffie": 29055, + "1623": 29056, + "beverley": 29057, + "schwarz": 29058, + "plunging": 29059, + "structurally": 29060, + "m3": 29061, + "rosenthal": 29062, + "vikram": 29063, + "##tsk": 29064, + "770": 29065, + "ghz": 29066, + "##onda": 29067, + "##tiv": 29068, + "chalmers": 29069, + "groningen": 29070, + "pew": 29071, + "reckon": 29072, + "unicef": 29073, + "##rvis": 29074, + "55th": 29075, + "##gni": 29076, + "1651": 29077, + "sulawesi": 29078, + "avila": 29079, + "cai": 29080, + "metaphysical": 29081, + "screwing": 29082, + "turbulence": 29083, + "##mberg": 29084, + "augusto": 29085, + "samba": 29086, + "56th": 29087, + "baffled": 29088, + "momentary": 29089, + "toxin": 29090, + "##urian": 29091, + "##wani": 29092, + "aachen": 29093, + "condoms": 29094, + "dali": 29095, + "steppe": 29096, + "##3d": 29097, + "##app": 29098, + "##oed": 29099, + "##year": 29100, + "adolescence": 29101, + "dauphin": 29102, + "electrically": 29103, + "inaccessible": 29104, + "microscopy": 29105, + "nikita": 29106, + "##ega": 29107, + "atv": 29108, + "##cel": 29109, + "##enter": 29110, + "##oles": 29111, + "##oteric": 29112, + "##ы": 29113, + "accountants": 29114, + "punishments": 29115, + "wrongly": 29116, + "bribes": 29117, + "adventurous": 29118, + "clinch": 29119, + "flinders": 29120, + "southland": 29121, + "##hem": 29122, + "##kata": 29123, + "gough": 29124, + "##ciency": 29125, + "lads": 29126, + "soared": 29127, + "##ה": 29128, + "undergoes": 29129, + "deformation": 29130, + "outlawed": 29131, + "rubbish": 29132, + "##arus": 29133, + "##mussen": 29134, + "##nidae": 29135, + "##rzburg": 29136, + "arcs": 29137, + "##ingdon": 29138, + "##tituted": 29139, + "1695": 29140, + "wheelbase": 29141, + "wheeling": 29142, + "bombardier": 29143, + "campground": 29144, + "zebra": 29145, + "##lices": 29146, + "##oj": 29147, + "##bain": 29148, + "lullaby": 29149, + "##ecure": 29150, + "donetsk": 29151, + "wylie": 29152, + "grenada": 29153, + "##arding": 29154, + "##ης": 29155, + "squinting": 29156, + "eireann": 29157, + "opposes": 29158, + "##andra": 29159, + "maximal": 29160, + "runes": 29161, + "##broken": 29162, + "##cuting": 29163, + "##iface": 29164, + "##ror": 29165, + "##rosis": 29166, + "additive": 29167, + "britney": 29168, + "adultery": 29169, + "triggering": 29170, + "##drome": 29171, + "detrimental": 29172, + "aarhus": 29173, + "containment": 29174, + "jc": 29175, + "swapped": 29176, + "vichy": 29177, + "##ioms": 29178, + "madly": 29179, + "##oric": 29180, + "##rag": 29181, + "brant": 29182, + "##ckey": 29183, + "##trix": 29184, + "1560": 29185, + "1612": 29186, + "broughton": 29187, + "rustling": 29188, + "##stems": 29189, + "##uder": 29190, + "asbestos": 29191, + "mentoring": 29192, + "##nivorous": 29193, + "finley": 29194, + "leaps": 29195, + "##isan": 29196, + "apical": 29197, + "pry": 29198, + "slits": 29199, + "substitutes": 29200, + "##dict": 29201, + "intuitive": 29202, + "fantasia": 29203, + "insistent": 29204, + "unreasonable": 29205, + "##igen": 29206, + "##vna": 29207, + "domed": 29208, + "hannover": 29209, + "margot": 29210, + "ponder": 29211, + "##zziness": 29212, + "impromptu": 29213, + "jian": 29214, + "lc": 29215, + "rampage": 29216, + "stemming": 29217, + "##eft": 29218, + "andrey": 29219, + "gerais": 29220, + "whichever": 29221, + "amnesia": 29222, + "appropriated": 29223, + "anzac": 29224, + "clicks": 29225, + "modifying": 29226, + "ultimatum": 29227, + "cambrian": 29228, + "maids": 29229, + "verve": 29230, + "yellowstone": 29231, + "##mbs": 29232, + "conservatoire": 29233, + "##scribe": 29234, + "adherence": 29235, + "dinners": 29236, + "spectra": 29237, + "imperfect": 29238, + "mysteriously": 29239, + "sidekick": 29240, + "tatar": 29241, + "tuba": 29242, + "##aks": 29243, + "##ifolia": 29244, + "distrust": 29245, + "##athan": 29246, + "##zle": 29247, + "c2": 29248, + "ronin": 29249, + "zac": 29250, + "##pse": 29251, + "celaena": 29252, + "instrumentalist": 29253, + "scents": 29254, + "skopje": 29255, + "##mbling": 29256, + "comical": 29257, + "compensated": 29258, + "vidal": 29259, + "condor": 29260, + "intersect": 29261, + "jingle": 29262, + "wavelengths": 29263, + "##urrent": 29264, + "mcqueen": 29265, + "##izzly": 29266, + "carp": 29267, + "weasel": 29268, + "422": 29269, + "kanye": 29270, + "militias": 29271, + "postdoctoral": 29272, + "eugen": 29273, + "gunslinger": 29274, + "##ɛ": 29275, + "faux": 29276, + "hospice": 29277, + "##for": 29278, + "appalled": 29279, + "derivation": 29280, + "dwarves": 29281, + "##elis": 29282, + "dilapidated": 29283, + "##folk": 29284, + "astoria": 29285, + "philology": 29286, + "##lwyn": 29287, + "##otho": 29288, + "##saka": 29289, + "inducing": 29290, + "philanthropy": 29291, + "##bf": 29292, + "##itative": 29293, + "geek": 29294, + "markedly": 29295, + "sql": 29296, + "##yce": 29297, + "bessie": 29298, + "indices": 29299, + "rn": 29300, + "##flict": 29301, + "495": 29302, + "frowns": 29303, + "resolving": 29304, + "weightlifting": 29305, + "tugs": 29306, + "cleric": 29307, + "contentious": 29308, + "1653": 29309, + "mania": 29310, + "rms": 29311, + "##miya": 29312, + "##reate": 29313, + "##ruck": 29314, + "##tucket": 29315, + "bien": 29316, + "eels": 29317, + "marek": 29318, + "##ayton": 29319, + "##cence": 29320, + "discreet": 29321, + "unofficially": 29322, + "##ife": 29323, + "leaks": 29324, + "##bber": 29325, + "1705": 29326, + "332": 29327, + "dung": 29328, + "compressor": 29329, + "hillsborough": 29330, + "pandit": 29331, + "shillings": 29332, + "distal": 29333, + "##skin": 29334, + "381": 29335, + "##tat": 29336, + "##you": 29337, + "nosed": 29338, + "##nir": 29339, + "mangrove": 29340, + "undeveloped": 29341, + "##idia": 29342, + "textures": 29343, + "##inho": 29344, + "##500": 29345, + "##rise": 29346, + "ae": 29347, + "irritating": 29348, + "nay": 29349, + "amazingly": 29350, + "bancroft": 29351, + "apologetic": 29352, + "compassionate": 29353, + "kata": 29354, + "symphonies": 29355, + "##lovic": 29356, + "airspace": 29357, + "##lch": 29358, + "930": 29359, + "gifford": 29360, + "precautions": 29361, + "fulfillment": 29362, + "sevilla": 29363, + "vulgar": 29364, + "martinique": 29365, + "##urities": 29366, + "looting": 29367, + "piccolo": 29368, + "tidy": 29369, + "##dermott": 29370, + "quadrant": 29371, + "armchair": 29372, + "incomes": 29373, + "mathematicians": 29374, + "stampede": 29375, + "nilsson": 29376, + "##inking": 29377, + "##scan": 29378, + "foo": 29379, + "quarterfinal": 29380, + "##ostal": 29381, + "shang": 29382, + "shouldered": 29383, + "squirrels": 29384, + "##owe": 29385, + "344": 29386, + "vinegar": 29387, + "##bner": 29388, + "##rchy": 29389, + "##systems": 29390, + "delaying": 29391, + "##trics": 29392, + "ars": 29393, + "dwyer": 29394, + "rhapsody": 29395, + "sponsoring": 29396, + "##gration": 29397, + "bipolar": 29398, + "cinder": 29399, + "starters": 29400, + "##olio": 29401, + "##urst": 29402, + "421": 29403, + "signage": 29404, + "##nty": 29405, + "aground": 29406, + "figurative": 29407, + "mons": 29408, + "acquaintances": 29409, + "duets": 29410, + "erroneously": 29411, + "soyuz": 29412, + "elliptic": 29413, + "recreated": 29414, + "##cultural": 29415, + "##quette": 29416, + "##ssed": 29417, + "##tma": 29418, + "##zcz": 29419, + "moderator": 29420, + "scares": 29421, + "##itaire": 29422, + "##stones": 29423, + "##udence": 29424, + "juniper": 29425, + "sighting": 29426, + "##just": 29427, + "##nsen": 29428, + "britten": 29429, + "calabria": 29430, + "ry": 29431, + "bop": 29432, + "cramer": 29433, + "forsyth": 29434, + "stillness": 29435, + "##л": 29436, + "airmen": 29437, + "gathers": 29438, + "unfit": 29439, + "##umber": 29440, + "##upt": 29441, + "taunting": 29442, + "##rip": 29443, + "seeker": 29444, + "streamlined": 29445, + "##bution": 29446, + "holster": 29447, + "schumann": 29448, + "tread": 29449, + "vox": 29450, + "##gano": 29451, + "##onzo": 29452, + "strive": 29453, + "dil": 29454, + "reforming": 29455, + "covent": 29456, + "newbury": 29457, + "predicting": 29458, + "##orro": 29459, + "decorate": 29460, + "tre": 29461, + "##puted": 29462, + "andover": 29463, + "ie": 29464, + "asahi": 29465, + "dept": 29466, + "dunkirk": 29467, + "gills": 29468, + "##tori": 29469, + "buren": 29470, + "huskies": 29471, + "##stis": 29472, + "##stov": 29473, + "abstracts": 29474, + "bets": 29475, + "loosen": 29476, + "##opa": 29477, + "1682": 29478, + "yearning": 29479, + "##glio": 29480, + "##sir": 29481, + "berman": 29482, + "effortlessly": 29483, + "enamel": 29484, + "napoli": 29485, + "persist": 29486, + "##peration": 29487, + "##uez": 29488, + "attache": 29489, + "elisa": 29490, + "b1": 29491, + "invitations": 29492, + "##kic": 29493, + "accelerating": 29494, + "reindeer": 29495, + "boardwalk": 29496, + "clutches": 29497, + "nelly": 29498, + "polka": 29499, + "starbucks": 29500, + "##kei": 29501, + "adamant": 29502, + "huey": 29503, + "lough": 29504, + "unbroken": 29505, + "adventurer": 29506, + "embroidery": 29507, + "inspecting": 29508, + "stanza": 29509, + "##ducted": 29510, + "naia": 29511, + "taluka": 29512, + "##pone": 29513, + "##roids": 29514, + "chases": 29515, + "deprivation": 29516, + "florian": 29517, + "##jing": 29518, + "##ppet": 29519, + "earthly": 29520, + "##lib": 29521, + "##ssee": 29522, + "colossal": 29523, + "foreigner": 29524, + "vet": 29525, + "freaks": 29526, + "patrice": 29527, + "rosewood": 29528, + "triassic": 29529, + "upstate": 29530, + "##pkins": 29531, + "dominates": 29532, + "ata": 29533, + "chants": 29534, + "ks": 29535, + "vo": 29536, + "##400": 29537, + "##bley": 29538, + "##raya": 29539, + "##rmed": 29540, + "555": 29541, + "agra": 29542, + "infiltrate": 29543, + "##ailing": 29544, + "##ilation": 29545, + "##tzer": 29546, + "##uppe": 29547, + "##werk": 29548, + "binoculars": 29549, + "enthusiast": 29550, + "fujian": 29551, + "squeak": 29552, + "##avs": 29553, + "abolitionist": 29554, + "almeida": 29555, + "boredom": 29556, + "hampstead": 29557, + "marsden": 29558, + "rations": 29559, + "##ands": 29560, + "inflated": 29561, + "334": 29562, + "bonuses": 29563, + "rosalie": 29564, + "patna": 29565, + "##rco": 29566, + "329": 29567, + "detachments": 29568, + "penitentiary": 29569, + "54th": 29570, + "flourishing": 29571, + "woolf": 29572, + "##dion": 29573, + "##etched": 29574, + "papyrus": 29575, + "##lster": 29576, + "##nsor": 29577, + "##toy": 29578, + "bobbed": 29579, + "dismounted": 29580, + "endelle": 29581, + "inhuman": 29582, + "motorola": 29583, + "tbs": 29584, + "wince": 29585, + "wreath": 29586, + "##ticus": 29587, + "hideout": 29588, + "inspections": 29589, + "sanjay": 29590, + "disgrace": 29591, + "infused": 29592, + "pudding": 29593, + "stalks": 29594, + "##urbed": 29595, + "arsenic": 29596, + "leases": 29597, + "##hyl": 29598, + "##rrard": 29599, + "collarbone": 29600, + "##waite": 29601, + "##wil": 29602, + "dowry": 29603, + "##bant": 29604, + "##edance": 29605, + "genealogical": 29606, + "nitrate": 29607, + "salamanca": 29608, + "scandals": 29609, + "thyroid": 29610, + "necessitated": 29611, + "##!": 29612, + "##\"": 29613, + "###": 29614, + "##$": 29615, + "##%": 29616, + "##&": 29617, + "##'": 29618, + "##(": 29619, + "##)": 29620, + "##*": 29621, + "##+": 29622, + "##,": 29623, + "##-": 29624, + "##.": 29625, + "##/": 29626, + "##:": 29627, + "##;": 29628, + "##<": 29629, + "##=": 29630, + "##>": 29631, + "##?": 29632, + "##@": 29633, + "##[": 29634, + "##\\": 29635, + "##]": 29636, + "##^": 29637, + "##_": 29638, + "##`": 29639, + "##{": 29640, + "##|": 29641, + "##}": 29642, + "##~": 29643, + "##¡": 29644, + "##¢": 29645, + "##£": 29646, + "##¤": 29647, + "##¥": 29648, + "##¦": 29649, + "##§": 29650, + "##¨": 29651, + "##©": 29652, + "##ª": 29653, + "##«": 29654, + "##¬": 29655, + "##®": 29656, + "##±": 29657, + "##´": 29658, + "##µ": 29659, + "##¶": 29660, + "##·": 29661, + "##º": 29662, + "##»": 29663, + "##¼": 29664, + "##¾": 29665, + "##¿": 29666, + "##æ": 29667, + "##ð": 29668, + "##÷": 29669, + "##þ": 29670, + "##đ": 29671, + "##ħ": 29672, + "##ŋ": 29673, + "##œ": 29674, + "##ƒ": 29675, + "##ɐ": 29676, + "##ɑ": 29677, + "##ɒ": 29678, + "##ɔ": 29679, + "##ɕ": 29680, + "##ə": 29681, + "##ɡ": 29682, + "##ɣ": 29683, + "##ɨ": 29684, + "##ɪ": 29685, + "##ɫ": 29686, + "##ɬ": 29687, + "##ɯ": 29688, + "##ɲ": 29689, + "##ɴ": 29690, + "##ɹ": 29691, + "##ɾ": 29692, + "##ʀ": 29693, + "##ʁ": 29694, + "##ʂ": 29695, + "##ʃ": 29696, + "##ʉ": 29697, + "##ʊ": 29698, + "##ʋ": 29699, + "##ʌ": 29700, + "##ʎ": 29701, + "##ʐ": 29702, + "##ʑ": 29703, + "##ʒ": 29704, + "##ʔ": 29705, + "##ʰ": 29706, + "##ʲ": 29707, + "##ʳ": 29708, + "##ʷ": 29709, + "##ʸ": 29710, + "##ʻ": 29711, + "##ʼ": 29712, + "##ʾ": 29713, + "##ʿ": 29714, + "##ˈ": 29715, + "##ˡ": 29716, + "##ˢ": 29717, + "##ˣ": 29718, + "##ˤ": 29719, + "##β": 29720, + "##γ": 29721, + "##δ": 29722, + "##ε": 29723, + "##ζ": 29724, + "##θ": 29725, + "##κ": 29726, + "##λ": 29727, + "##μ": 29728, + "##ξ": 29729, + "##ο": 29730, + "##π": 29731, + "##ρ": 29732, + "##σ": 29733, + "##τ": 29734, + "##υ": 29735, + "##φ": 29736, + "##χ": 29737, + "##ψ": 29738, + "##ω": 29739, + "##б": 29740, + "##г": 29741, + "##д": 29742, + "##ж": 29743, + "##з": 29744, + "##м": 29745, + "##п": 29746, + "##с": 29747, + "##у": 29748, + "##ф": 29749, + "##х": 29750, + "##ц": 29751, + "##ч": 29752, + "##ш": 29753, + "##щ": 29754, + "##ъ": 29755, + "##э": 29756, + "##ю": 29757, + "##ђ": 29758, + "##є": 29759, + "##і": 29760, + "##ј": 29761, + "##љ": 29762, + "##њ": 29763, + "##ћ": 29764, + "##ӏ": 29765, + "##ա": 29766, + "##բ": 29767, + "##գ": 29768, + "##դ": 29769, + "##ե": 29770, + "##թ": 29771, + "##ի": 29772, + "##լ": 29773, + "##կ": 29774, + "##հ": 29775, + "##մ": 29776, + "##յ": 29777, + "##ն": 29778, + "##ո": 29779, + "##պ": 29780, + "##ս": 29781, + "##վ": 29782, + "##տ": 29783, + "##ր": 29784, + "##ւ": 29785, + "##ք": 29786, + "##־": 29787, + "##א": 29788, + "##ב": 29789, + "##ג": 29790, + "##ד": 29791, + "##ו": 29792, + "##ז": 29793, + "##ח": 29794, + "##ט": 29795, + "##י": 29796, + "##ך": 29797, + "##כ": 29798, + "##ל": 29799, + "##ם": 29800, + "##מ": 29801, + "##ן": 29802, + "##נ": 29803, + "##ס": 29804, + "##ע": 29805, + "##ף": 29806, + "##פ": 29807, + "##ץ": 29808, + "##צ": 29809, + "##ק": 29810, + "##ר": 29811, + "##ש": 29812, + "##ת": 29813, + "##،": 29814, + "##ء": 29815, + "##ب": 29816, + "##ت": 29817, + "##ث": 29818, + "##ج": 29819, + "##ح": 29820, + "##خ": 29821, + "##ذ": 29822, + "##ز": 29823, + "##س": 29824, + "##ش": 29825, + "##ص": 29826, + "##ض": 29827, + "##ط": 29828, + "##ظ": 29829, + "##ع": 29830, + "##غ": 29831, + "##ـ": 29832, + "##ف": 29833, + "##ق": 29834, + "##ك": 29835, + "##و": 29836, + "##ى": 29837, + "##ٹ": 29838, + "##پ": 29839, + "##چ": 29840, + "##ک": 29841, + "##گ": 29842, + "##ں": 29843, + "##ھ": 29844, + "##ہ": 29845, + "##ے": 29846, + "##अ": 29847, + "##आ": 29848, + "##उ": 29849, + "##ए": 29850, + "##क": 29851, + "##ख": 29852, + "##ग": 29853, + "##च": 29854, + "##ज": 29855, + "##ट": 29856, + "##ड": 29857, + "##ण": 29858, + "##त": 29859, + "##थ": 29860, + "##द": 29861, + "##ध": 29862, + "##न": 29863, + "##प": 29864, + "##ब": 29865, + "##भ": 29866, + "##म": 29867, + "##य": 29868, + "##र": 29869, + "##ल": 29870, + "##व": 29871, + "##श": 29872, + "##ष": 29873, + "##स": 29874, + "##ह": 29875, + "##ा": 29876, + "##ि": 29877, + "##ी": 29878, + "##ो": 29879, + "##।": 29880, + "##॥": 29881, + "##ং": 29882, + "##অ": 29883, + "##আ": 29884, + "##ই": 29885, + "##উ": 29886, + "##এ": 29887, + "##ও": 29888, + "##ক": 29889, + "##খ": 29890, + "##গ": 29891, + "##চ": 29892, + "##ছ": 29893, + "##জ": 29894, + "##ট": 29895, + "##ড": 29896, + "##ণ": 29897, + "##ত": 29898, + "##থ": 29899, + "##দ": 29900, + "##ধ": 29901, + "##ন": 29902, + "##প": 29903, + "##ব": 29904, + "##ভ": 29905, + "##ম": 29906, + "##য": 29907, + "##র": 29908, + "##ল": 29909, + "##শ": 29910, + "##ষ": 29911, + "##স": 29912, + "##হ": 29913, + "##া": 29914, + "##ি": 29915, + "##ী": 29916, + "##ে": 29917, + "##க": 29918, + "##ச": 29919, + "##ட": 29920, + "##த": 29921, + "##ந": 29922, + "##ன": 29923, + "##ப": 29924, + "##ம": 29925, + "##ய": 29926, + "##ர": 29927, + "##ல": 29928, + "##ள": 29929, + "##வ": 29930, + "##ா": 29931, + "##ி": 29932, + "##ு": 29933, + "##ே": 29934, + "##ை": 29935, + "##ನ": 29936, + "##ರ": 29937, + "##ಾ": 29938, + "##ක": 29939, + "##ය": 29940, + "##ර": 29941, + "##ල": 29942, + "##ව": 29943, + "##ා": 29944, + "##ก": 29945, + "##ง": 29946, + "##ต": 29947, + "##ท": 29948, + "##น": 29949, + "##พ": 29950, + "##ม": 29951, + "##ย": 29952, + "##ร": 29953, + "##ล": 29954, + "##ว": 29955, + "##ส": 29956, + "##อ": 29957, + "##า": 29958, + "##เ": 29959, + "##་": 29960, + "##།": 29961, + "##ག": 29962, + "##ང": 29963, + "##ད": 29964, + "##ན": 29965, + "##པ": 29966, + "##བ": 29967, + "##མ": 29968, + "##འ": 29969, + "##ར": 29970, + "##ལ": 29971, + "##ས": 29972, + "##မ": 29973, + "##ა": 29974, + "##ბ": 29975, + "##გ": 29976, + "##დ": 29977, + "##ე": 29978, + "##ვ": 29979, + "##თ": 29980, + "##ი": 29981, + "##კ": 29982, + "##ლ": 29983, + "##მ": 29984, + "##ნ": 29985, + "##ო": 29986, + "##რ": 29987, + "##ს": 29988, + "##ტ": 29989, + "##უ": 29990, + "##ᄀ": 29991, + "##ᄂ": 29992, + "##ᄃ": 29993, + "##ᄅ": 29994, + "##ᄆ": 29995, + "##ᄇ": 29996, + "##ᄉ": 29997, + "##ᄊ": 29998, + "##ᄋ": 29999, + "##ᄌ": 30000, + "##ᄎ": 30001, + "##ᄏ": 30002, + "##ᄐ": 30003, + "##ᄑ": 30004, + "##ᄒ": 30005, + "##ᅡ": 30006, + "##ᅢ": 30007, + "##ᅥ": 30008, + "##ᅦ": 30009, + "##ᅧ": 30010, + "##ᅩ": 30011, + "##ᅪ": 30012, + "##ᅭ": 30013, + "##ᅮ": 30014, + "##ᅯ": 30015, + "##ᅲ": 30016, + "##ᅳ": 30017, + "##ᅴ": 30018, + "##ᅵ": 30019, + "##ᆨ": 30020, + "##ᆫ": 30021, + "##ᆯ": 30022, + "##ᆷ": 30023, + "##ᆸ": 30024, + "##ᆼ": 30025, + "##ᴬ": 30026, + "##ᴮ": 30027, + "##ᴰ": 30028, + "##ᴵ": 30029, + "##ᴺ": 30030, + "##ᵀ": 30031, + "##ᵃ": 30032, + "##ᵇ": 30033, + "##ᵈ": 30034, + "##ᵉ": 30035, + "##ᵍ": 30036, + "##ᵏ": 30037, + "##ᵐ": 30038, + "##ᵒ": 30039, + "##ᵖ": 30040, + "##ᵗ": 30041, + "##ᵘ": 30042, + "##ᵣ": 30043, + "##ᵤ": 30044, + "##ᵥ": 30045, + "##ᶜ": 30046, + "##ᶠ": 30047, + "##‐": 30048, + "##‑": 30049, + "##‒": 30050, + "##–": 30051, + "##—": 30052, + "##―": 30053, + "##‖": 30054, + "##‘": 30055, + "##’": 30056, + "##‚": 30057, + "##“": 30058, + "##”": 30059, + "##„": 30060, + "##†": 30061, + "##‡": 30062, + "##•": 30063, + "##…": 30064, + "##‰": 30065, + "##′": 30066, + "##″": 30067, + "##›": 30068, + "##‿": 30069, + "##⁄": 30070, + "##⁰": 30071, + "##ⁱ": 30072, + "##⁴": 30073, + "##⁵": 30074, + "##⁶": 30075, + "##⁷": 30076, + "##⁸": 30077, + "##⁹": 30078, + "##⁻": 30079, + "##ⁿ": 30080, + "##₅": 30081, + "##₆": 30082, + "##₇": 30083, + "##₈": 30084, + "##₉": 30085, + "##₊": 30086, + "##₍": 30087, + "##₎": 30088, + "##ₐ": 30089, + "##ₑ": 30090, + "##ₒ": 30091, + "##ₓ": 30092, + "##ₕ": 30093, + "##ₖ": 30094, + "##ₗ": 30095, + "##ₘ": 30096, + "##ₚ": 30097, + "##ₛ": 30098, + "##ₜ": 30099, + "##₤": 30100, + "##₩": 30101, + "##€": 30102, + "##₱": 30103, + "##₹": 30104, + "##ℓ": 30105, + "##№": 30106, + "##ℝ": 30107, + "##™": 30108, + "##⅓": 30109, + "##⅔": 30110, + "##←": 30111, + "##↑": 30112, + "##→": 30113, + "##↓": 30114, + "##↔": 30115, + "##↦": 30116, + "##⇄": 30117, + "##⇌": 30118, + "##⇒": 30119, + "##∂": 30120, + "##∅": 30121, + "##∆": 30122, + "##∇": 30123, + "##∈": 30124, + "##∗": 30125, + "##∘": 30126, + "##√": 30127, + "##∞": 30128, + "##∧": 30129, + "##∨": 30130, + "##∩": 30131, + "##∪": 30132, + "##≈": 30133, + "##≡": 30134, + "##≤": 30135, + "##≥": 30136, + "##⊂": 30137, + "##⊆": 30138, + "##⊕": 30139, + "##⊗": 30140, + "##⋅": 30141, + "##─": 30142, + "##│": 30143, + "##■": 30144, + "##▪": 30145, + "##●": 30146, + "##★": 30147, + "##☆": 30148, + "##☉": 30149, + "##♠": 30150, + "##♣": 30151, + "##♥": 30152, + "##♦": 30153, + "##♯": 30154, + "##⟨": 30155, + "##⟩": 30156, + "##ⱼ": 30157, + "##⺩": 30158, + "##⺼": 30159, + "##⽥": 30160, + "##、": 30161, + "##。": 30162, + "##〈": 30163, + "##〉": 30164, + "##《": 30165, + "##》": 30166, + "##「": 30167, + "##」": 30168, + "##『": 30169, + "##』": 30170, + "##〜": 30171, + "##あ": 30172, + "##い": 30173, + "##う": 30174, + "##え": 30175, + "##お": 30176, + "##か": 30177, + "##き": 30178, + "##く": 30179, + "##け": 30180, + "##こ": 30181, + "##さ": 30182, + "##し": 30183, + "##す": 30184, + "##せ": 30185, + "##そ": 30186, + "##た": 30187, + "##ち": 30188, + "##っ": 30189, + "##つ": 30190, + "##て": 30191, + "##と": 30192, + "##な": 30193, + "##に": 30194, + "##ぬ": 30195, + "##ね": 30196, + "##の": 30197, + "##は": 30198, + "##ひ": 30199, + "##ふ": 30200, + "##へ": 30201, + "##ほ": 30202, + "##ま": 30203, + "##み": 30204, + "##む": 30205, + "##め": 30206, + "##も": 30207, + "##や": 30208, + "##ゆ": 30209, + "##よ": 30210, + "##ら": 30211, + "##り": 30212, + "##る": 30213, + "##れ": 30214, + "##ろ": 30215, + "##を": 30216, + "##ん": 30217, + "##ァ": 30218, + "##ア": 30219, + "##ィ": 30220, + "##イ": 30221, + "##ウ": 30222, + "##ェ": 30223, + "##エ": 30224, + "##オ": 30225, + "##カ": 30226, + "##キ": 30227, + "##ク": 30228, + "##ケ": 30229, + "##コ": 30230, + "##サ": 30231, + "##シ": 30232, + "##ス": 30233, + "##セ": 30234, + "##タ": 30235, + "##チ": 30236, + "##ッ": 30237, + "##ツ": 30238, + "##テ": 30239, + "##ト": 30240, + "##ナ": 30241, + "##ニ": 30242, + "##ノ": 30243, + "##ハ": 30244, + "##ヒ": 30245, + "##フ": 30246, + "##ヘ": 30247, + "##ホ": 30248, + "##マ": 30249, + "##ミ": 30250, + "##ム": 30251, + "##メ": 30252, + "##モ": 30253, + "##ャ": 30254, + "##ュ": 30255, + "##ョ": 30256, + "##ラ": 30257, + "##リ": 30258, + "##ル": 30259, + "##レ": 30260, + "##ロ": 30261, + "##ワ": 30262, + "##ン": 30263, + "##・": 30264, + "##ー": 30265, + "##一": 30266, + "##三": 30267, + "##上": 30268, + "##下": 30269, + "##不": 30270, + "##世": 30271, + "##中": 30272, + "##主": 30273, + "##久": 30274, + "##之": 30275, + "##也": 30276, + "##事": 30277, + "##二": 30278, + "##五": 30279, + "##井": 30280, + "##京": 30281, + "##人": 30282, + "##亻": 30283, + "##仁": 30284, + "##介": 30285, + "##代": 30286, + "##仮": 30287, + "##伊": 30288, + "##会": 30289, + "##佐": 30290, + "##侍": 30291, + "##保": 30292, + "##信": 30293, + "##健": 30294, + "##元": 30295, + "##光": 30296, + "##八": 30297, + "##公": 30298, + "##内": 30299, + "##出": 30300, + "##分": 30301, + "##前": 30302, + "##劉": 30303, + "##力": 30304, + "##加": 30305, + "##勝": 30306, + "##北": 30307, + "##区": 30308, + "##十": 30309, + "##千": 30310, + "##南": 30311, + "##博": 30312, + "##原": 30313, + "##口": 30314, + "##古": 30315, + "##史": 30316, + "##司": 30317, + "##合": 30318, + "##吉": 30319, + "##同": 30320, + "##名": 30321, + "##和": 30322, + "##囗": 30323, + "##四": 30324, + "##国": 30325, + "##國": 30326, + "##土": 30327, + "##地": 30328, + "##坂": 30329, + "##城": 30330, + "##堂": 30331, + "##場": 30332, + "##士": 30333, + "##夏": 30334, + "##外": 30335, + "##大": 30336, + "##天": 30337, + "##太": 30338, + "##夫": 30339, + "##奈": 30340, + "##女": 30341, + "##子": 30342, + "##学": 30343, + "##宀": 30344, + "##宇": 30345, + "##安": 30346, + "##宗": 30347, + "##定": 30348, + "##宣": 30349, + "##宮": 30350, + "##家": 30351, + "##宿": 30352, + "##寺": 30353, + "##將": 30354, + "##小": 30355, + "##尚": 30356, + "##山": 30357, + "##岡": 30358, + "##島": 30359, + "##崎": 30360, + "##川": 30361, + "##州": 30362, + "##巿": 30363, + "##帝": 30364, + "##平": 30365, + "##年": 30366, + "##幸": 30367, + "##广": 30368, + "##弘": 30369, + "##張": 30370, + "##彳": 30371, + "##後": 30372, + "##御": 30373, + "##德": 30374, + "##心": 30375, + "##忄": 30376, + "##志": 30377, + "##忠": 30378, + "##愛": 30379, + "##成": 30380, + "##我": 30381, + "##戦": 30382, + "##戸": 30383, + "##手": 30384, + "##扌": 30385, + "##政": 30386, + "##文": 30387, + "##新": 30388, + "##方": 30389, + "##日": 30390, + "##明": 30391, + "##星": 30392, + "##春": 30393, + "##昭": 30394, + "##智": 30395, + "##曲": 30396, + "##書": 30397, + "##月": 30398, + "##有": 30399, + "##朝": 30400, + "##木": 30401, + "##本": 30402, + "##李": 30403, + "##村": 30404, + "##東": 30405, + "##松": 30406, + "##林": 30407, + "##森": 30408, + "##楊": 30409, + "##樹": 30410, + "##橋": 30411, + "##歌": 30412, + "##止": 30413, + "##正": 30414, + "##武": 30415, + "##比": 30416, + "##氏": 30417, + "##民": 30418, + "##水": 30419, + "##氵": 30420, + "##氷": 30421, + "##永": 30422, + "##江": 30423, + "##沢": 30424, + "##河": 30425, + "##治": 30426, + "##法": 30427, + "##海": 30428, + "##清": 30429, + "##漢": 30430, + "##瀬": 30431, + "##火": 30432, + "##版": 30433, + "##犬": 30434, + "##王": 30435, + "##生": 30436, + "##田": 30437, + "##男": 30438, + "##疒": 30439, + "##発": 30440, + "##白": 30441, + "##的": 30442, + "##皇": 30443, + "##目": 30444, + "##相": 30445, + "##省": 30446, + "##真": 30447, + "##石": 30448, + "##示": 30449, + "##社": 30450, + "##神": 30451, + "##福": 30452, + "##禾": 30453, + "##秀": 30454, + "##秋": 30455, + "##空": 30456, + "##立": 30457, + "##章": 30458, + "##竹": 30459, + "##糹": 30460, + "##美": 30461, + "##義": 30462, + "##耳": 30463, + "##良": 30464, + "##艹": 30465, + "##花": 30466, + "##英": 30467, + "##華": 30468, + "##葉": 30469, + "##藤": 30470, + "##行": 30471, + "##街": 30472, + "##西": 30473, + "##見": 30474, + "##訁": 30475, + "##語": 30476, + "##谷": 30477, + "##貝": 30478, + "##貴": 30479, + "##車": 30480, + "##軍": 30481, + "##辶": 30482, + "##道": 30483, + "##郎": 30484, + "##郡": 30485, + "##部": 30486, + "##都": 30487, + "##里": 30488, + "##野": 30489, + "##金": 30490, + "##鈴": 30491, + "##镇": 30492, + "##長": 30493, + "##門": 30494, + "##間": 30495, + "##阝": 30496, + "##阿": 30497, + "##陳": 30498, + "##陽": 30499, + "##雄": 30500, + "##青": 30501, + "##面": 30502, + "##風": 30503, + "##食": 30504, + "##香": 30505, + "##馬": 30506, + "##高": 30507, + "##龍": 30508, + "##龸": 30509, + "##fi": 30510, + "##fl": 30511, + "##!": 30512, + "##(": 30513, + "##)": 30514, + "##,": 30515, + "##-": 30516, + "##.": 30517, + "##/": 30518, + "##:": 30519, + "##?": 30520, + "##~": 30521 + } + } +} \ No newline at end of file diff --git a/flow-Agent/models/mxbai-embed-large-v1/tokenizer_config.json b/flow-Agent/models/mxbai-embed-large-v1/tokenizer_config.json new file mode 100644 index 0000000..7530565 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/tokenizer_config.json @@ -0,0 +1,57 @@ +{ + "added_tokens_decoder": { + "0": { + "content": "[PAD]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "100": { + "content": "[UNK]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "101": { + "content": "[CLS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "102": { + "content": "[SEP]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "103": { + "content": "[MASK]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + } + }, + "clean_up_tokenization_spaces": true, + "cls_token": "[CLS]", + "do_basic_tokenize": true, + "do_lower_case": true, + "mask_token": "[MASK]", + "model_max_length": 512, + "never_split": null, + "pad_token": "[PAD]", + "sep_token": "[SEP]", + "strip_accents": null, + "tokenize_chinese_chars": true, + "tokenizer_class": "BertTokenizer", + "unk_token": "[UNK]" +} diff --git a/flow-Agent/models/mxbai-embed-large-v1/vocab.txt b/flow-Agent/models/mxbai-embed-large-v1/vocab.txt new file mode 100644 index 0000000..fb14027 --- /dev/null +++ b/flow-Agent/models/mxbai-embed-large-v1/vocab.txt @@ -0,0 +1,30522 @@ +[PAD] +[unused0] +[unused1] +[unused2] +[unused3] +[unused4] +[unused5] +[unused6] +[unused7] +[unused8] +[unused9] +[unused10] +[unused11] +[unused12] +[unused13] +[unused14] +[unused15] +[unused16] +[unused17] +[unused18] +[unused19] +[unused20] +[unused21] +[unused22] +[unused23] +[unused24] +[unused25] +[unused26] +[unused27] +[unused28] +[unused29] +[unused30] +[unused31] +[unused32] +[unused33] +[unused34] +[unused35] +[unused36] +[unused37] +[unused38] +[unused39] +[unused40] +[unused41] +[unused42] +[unused43] +[unused44] +[unused45] +[unused46] +[unused47] +[unused48] +[unused49] +[unused50] +[unused51] +[unused52] +[unused53] +[unused54] +[unused55] +[unused56] +[unused57] +[unused58] +[unused59] +[unused60] +[unused61] +[unused62] +[unused63] +[unused64] +[unused65] +[unused66] +[unused67] +[unused68] +[unused69] +[unused70] +[unused71] +[unused72] +[unused73] +[unused74] +[unused75] +[unused76] +[unused77] +[unused78] +[unused79] +[unused80] +[unused81] +[unused82] +[unused83] +[unused84] +[unused85] +[unused86] +[unused87] +[unused88] +[unused89] +[unused90] +[unused91] +[unused92] +[unused93] +[unused94] +[unused95] +[unused96] +[unused97] +[unused98] +[UNK] +[CLS] +[SEP] +[MASK] +[unused99] +[unused100] +[unused101] +[unused102] +[unused103] +[unused104] +[unused105] +[unused106] +[unused107] +[unused108] +[unused109] +[unused110] +[unused111] +[unused112] +[unused113] +[unused114] +[unused115] +[unused116] +[unused117] +[unused118] +[unused119] +[unused120] +[unused121] +[unused122] +[unused123] +[unused124] +[unused125] +[unused126] +[unused127] +[unused128] +[unused129] +[unused130] +[unused131] +[unused132] +[unused133] +[unused134] +[unused135] +[unused136] +[unused137] +[unused138] +[unused139] +[unused140] +[unused141] +[unused142] +[unused143] +[unused144] +[unused145] +[unused146] +[unused147] +[unused148] +[unused149] +[unused150] +[unused151] +[unused152] +[unused153] +[unused154] +[unused155] +[unused156] +[unused157] +[unused158] +[unused159] +[unused160] +[unused161] +[unused162] +[unused163] +[unused164] +[unused165] +[unused166] +[unused167] +[unused168] +[unused169] +[unused170] +[unused171] +[unused172] +[unused173] +[unused174] +[unused175] +[unused176] +[unused177] +[unused178] +[unused179] +[unused180] +[unused181] +[unused182] +[unused183] +[unused184] +[unused185] +[unused186] +[unused187] +[unused188] +[unused189] +[unused190] +[unused191] +[unused192] +[unused193] +[unused194] +[unused195] +[unused196] +[unused197] +[unused198] +[unused199] +[unused200] +[unused201] +[unused202] +[unused203] +[unused204] +[unused205] +[unused206] +[unused207] +[unused208] +[unused209] +[unused210] +[unused211] +[unused212] +[unused213] +[unused214] +[unused215] +[unused216] +[unused217] +[unused218] +[unused219] +[unused220] +[unused221] +[unused222] +[unused223] +[unused224] +[unused225] +[unused226] +[unused227] +[unused228] +[unused229] +[unused230] +[unused231] +[unused232] +[unused233] +[unused234] +[unused235] +[unused236] +[unused237] +[unused238] +[unused239] +[unused240] +[unused241] +[unused242] +[unused243] +[unused244] +[unused245] +[unused246] +[unused247] +[unused248] +[unused249] +[unused250] +[unused251] +[unused252] +[unused253] +[unused254] +[unused255] +[unused256] +[unused257] +[unused258] +[unused259] +[unused260] +[unused261] +[unused262] +[unused263] +[unused264] +[unused265] +[unused266] +[unused267] +[unused268] +[unused269] +[unused270] +[unused271] +[unused272] +[unused273] +[unused274] +[unused275] +[unused276] +[unused277] +[unused278] +[unused279] +[unused280] +[unused281] +[unused282] +[unused283] +[unused284] +[unused285] +[unused286] +[unused287] +[unused288] +[unused289] +[unused290] +[unused291] +[unused292] +[unused293] +[unused294] +[unused295] +[unused296] +[unused297] +[unused298] +[unused299] +[unused300] +[unused301] +[unused302] +[unused303] +[unused304] +[unused305] +[unused306] +[unused307] +[unused308] +[unused309] +[unused310] +[unused311] +[unused312] +[unused313] +[unused314] +[unused315] +[unused316] +[unused317] +[unused318] +[unused319] +[unused320] +[unused321] +[unused322] +[unused323] +[unused324] +[unused325] +[unused326] +[unused327] +[unused328] +[unused329] +[unused330] +[unused331] +[unused332] +[unused333] +[unused334] +[unused335] +[unused336] +[unused337] +[unused338] +[unused339] +[unused340] +[unused341] +[unused342] +[unused343] +[unused344] +[unused345] +[unused346] +[unused347] +[unused348] +[unused349] +[unused350] +[unused351] +[unused352] +[unused353] +[unused354] +[unused355] +[unused356] +[unused357] +[unused358] +[unused359] +[unused360] +[unused361] +[unused362] +[unused363] +[unused364] +[unused365] +[unused366] +[unused367] +[unused368] +[unused369] +[unused370] +[unused371] +[unused372] +[unused373] +[unused374] +[unused375] +[unused376] +[unused377] +[unused378] +[unused379] +[unused380] +[unused381] +[unused382] +[unused383] +[unused384] +[unused385] +[unused386] +[unused387] +[unused388] +[unused389] +[unused390] +[unused391] +[unused392] +[unused393] +[unused394] +[unused395] +[unused396] +[unused397] +[unused398] +[unused399] +[unused400] +[unused401] +[unused402] +[unused403] +[unused404] +[unused405] +[unused406] +[unused407] +[unused408] +[unused409] +[unused410] +[unused411] +[unused412] +[unused413] +[unused414] +[unused415] +[unused416] +[unused417] +[unused418] +[unused419] +[unused420] +[unused421] +[unused422] +[unused423] +[unused424] +[unused425] +[unused426] +[unused427] +[unused428] +[unused429] +[unused430] +[unused431] +[unused432] +[unused433] +[unused434] +[unused435] +[unused436] +[unused437] +[unused438] +[unused439] +[unused440] +[unused441] +[unused442] +[unused443] +[unused444] +[unused445] +[unused446] +[unused447] +[unused448] +[unused449] +[unused450] +[unused451] +[unused452] +[unused453] +[unused454] +[unused455] +[unused456] +[unused457] +[unused458] +[unused459] +[unused460] +[unused461] +[unused462] +[unused463] +[unused464] +[unused465] +[unused466] +[unused467] +[unused468] +[unused469] +[unused470] +[unused471] +[unused472] +[unused473] +[unused474] +[unused475] +[unused476] +[unused477] +[unused478] +[unused479] +[unused480] +[unused481] +[unused482] +[unused483] +[unused484] +[unused485] +[unused486] +[unused487] +[unused488] +[unused489] +[unused490] +[unused491] +[unused492] +[unused493] +[unused494] +[unused495] +[unused496] +[unused497] +[unused498] +[unused499] +[unused500] +[unused501] +[unused502] +[unused503] +[unused504] +[unused505] +[unused506] +[unused507] +[unused508] +[unused509] +[unused510] +[unused511] +[unused512] +[unused513] +[unused514] +[unused515] +[unused516] +[unused517] +[unused518] +[unused519] +[unused520] +[unused521] +[unused522] +[unused523] +[unused524] +[unused525] +[unused526] +[unused527] +[unused528] +[unused529] +[unused530] +[unused531] +[unused532] +[unused533] +[unused534] +[unused535] +[unused536] +[unused537] +[unused538] +[unused539] +[unused540] +[unused541] +[unused542] +[unused543] +[unused544] +[unused545] +[unused546] +[unused547] +[unused548] +[unused549] +[unused550] +[unused551] +[unused552] +[unused553] +[unused554] +[unused555] +[unused556] +[unused557] +[unused558] +[unused559] +[unused560] +[unused561] +[unused562] +[unused563] +[unused564] +[unused565] +[unused566] +[unused567] +[unused568] +[unused569] +[unused570] +[unused571] +[unused572] +[unused573] +[unused574] +[unused575] +[unused576] +[unused577] +[unused578] +[unused579] +[unused580] +[unused581] +[unused582] +[unused583] +[unused584] +[unused585] +[unused586] +[unused587] +[unused588] +[unused589] +[unused590] +[unused591] +[unused592] +[unused593] +[unused594] +[unused595] +[unused596] +[unused597] +[unused598] +[unused599] +[unused600] +[unused601] +[unused602] +[unused603] +[unused604] +[unused605] +[unused606] +[unused607] +[unused608] +[unused609] +[unused610] +[unused611] +[unused612] +[unused613] +[unused614] +[unused615] +[unused616] +[unused617] +[unused618] +[unused619] +[unused620] +[unused621] +[unused622] +[unused623] +[unused624] +[unused625] +[unused626] +[unused627] +[unused628] +[unused629] +[unused630] +[unused631] +[unused632] +[unused633] +[unused634] +[unused635] +[unused636] +[unused637] +[unused638] +[unused639] +[unused640] +[unused641] +[unused642] +[unused643] +[unused644] +[unused645] +[unused646] +[unused647] +[unused648] +[unused649] +[unused650] +[unused651] +[unused652] +[unused653] +[unused654] +[unused655] +[unused656] +[unused657] +[unused658] +[unused659] +[unused660] +[unused661] +[unused662] +[unused663] +[unused664] +[unused665] +[unused666] +[unused667] +[unused668] +[unused669] +[unused670] +[unused671] +[unused672] +[unused673] +[unused674] +[unused675] +[unused676] +[unused677] +[unused678] +[unused679] +[unused680] +[unused681] +[unused682] +[unused683] +[unused684] +[unused685] +[unused686] +[unused687] +[unused688] +[unused689] +[unused690] +[unused691] +[unused692] +[unused693] +[unused694] +[unused695] +[unused696] +[unused697] +[unused698] +[unused699] +[unused700] +[unused701] +[unused702] +[unused703] +[unused704] +[unused705] +[unused706] +[unused707] +[unused708] +[unused709] +[unused710] +[unused711] +[unused712] +[unused713] +[unused714] +[unused715] +[unused716] +[unused717] +[unused718] +[unused719] +[unused720] +[unused721] +[unused722] +[unused723] +[unused724] +[unused725] +[unused726] +[unused727] +[unused728] +[unused729] +[unused730] +[unused731] +[unused732] +[unused733] +[unused734] +[unused735] +[unused736] +[unused737] +[unused738] +[unused739] +[unused740] +[unused741] +[unused742] +[unused743] +[unused744] +[unused745] +[unused746] +[unused747] +[unused748] +[unused749] +[unused750] +[unused751] +[unused752] +[unused753] +[unused754] +[unused755] +[unused756] +[unused757] +[unused758] +[unused759] +[unused760] +[unused761] +[unused762] +[unused763] +[unused764] +[unused765] +[unused766] +[unused767] +[unused768] +[unused769] +[unused770] +[unused771] +[unused772] +[unused773] +[unused774] +[unused775] +[unused776] +[unused777] +[unused778] +[unused779] +[unused780] +[unused781] +[unused782] +[unused783] +[unused784] +[unused785] +[unused786] +[unused787] +[unused788] +[unused789] +[unused790] +[unused791] +[unused792] +[unused793] +[unused794] +[unused795] +[unused796] +[unused797] +[unused798] +[unused799] +[unused800] +[unused801] +[unused802] +[unused803] +[unused804] +[unused805] +[unused806] +[unused807] +[unused808] +[unused809] +[unused810] +[unused811] +[unused812] +[unused813] +[unused814] +[unused815] +[unused816] +[unused817] +[unused818] +[unused819] +[unused820] +[unused821] +[unused822] +[unused823] +[unused824] +[unused825] +[unused826] +[unused827] +[unused828] +[unused829] +[unused830] +[unused831] +[unused832] +[unused833] +[unused834] +[unused835] +[unused836] +[unused837] +[unused838] +[unused839] +[unused840] +[unused841] +[unused842] +[unused843] +[unused844] +[unused845] +[unused846] +[unused847] +[unused848] +[unused849] +[unused850] +[unused851] +[unused852] +[unused853] +[unused854] +[unused855] +[unused856] +[unused857] +[unused858] +[unused859] +[unused860] +[unused861] +[unused862] +[unused863] +[unused864] +[unused865] +[unused866] +[unused867] +[unused868] +[unused869] +[unused870] +[unused871] +[unused872] +[unused873] +[unused874] +[unused875] +[unused876] +[unused877] +[unused878] +[unused879] +[unused880] +[unused881] +[unused882] +[unused883] +[unused884] +[unused885] +[unused886] +[unused887] +[unused888] +[unused889] +[unused890] +[unused891] +[unused892] +[unused893] +[unused894] +[unused895] +[unused896] +[unused897] +[unused898] +[unused899] +[unused900] +[unused901] +[unused902] +[unused903] +[unused904] +[unused905] +[unused906] +[unused907] +[unused908] +[unused909] +[unused910] +[unused911] +[unused912] +[unused913] +[unused914] +[unused915] +[unused916] +[unused917] +[unused918] +[unused919] +[unused920] +[unused921] +[unused922] +[unused923] +[unused924] +[unused925] +[unused926] +[unused927] +[unused928] +[unused929] +[unused930] +[unused931] +[unused932] +[unused933] +[unused934] +[unused935] +[unused936] +[unused937] +[unused938] +[unused939] +[unused940] +[unused941] +[unused942] +[unused943] +[unused944] +[unused945] +[unused946] +[unused947] +[unused948] +[unused949] +[unused950] +[unused951] +[unused952] +[unused953] +[unused954] +[unused955] +[unused956] +[unused957] +[unused958] +[unused959] +[unused960] +[unused961] +[unused962] +[unused963] +[unused964] +[unused965] +[unused966] +[unused967] +[unused968] +[unused969] +[unused970] +[unused971] +[unused972] +[unused973] +[unused974] +[unused975] +[unused976] +[unused977] +[unused978] +[unused979] +[unused980] +[unused981] +[unused982] +[unused983] +[unused984] +[unused985] +[unused986] +[unused987] +[unused988] +[unused989] +[unused990] +[unused991] +[unused992] +[unused993] +! +" +# +$ +% +& +' +( +) +* ++ +, +- +. +/ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +: +; +< += +> +? +@ +[ +\ +] +^ +_ +` +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +{ +| +} +~ +¡ +¢ +£ +¤ +¥ +¦ +§ +¨ +© +ª +« +¬ +® +° +± +² +³ +´ +µ +¶ +· +¹ +º +» +¼ +½ +¾ +¿ +× +ß +æ +ð +÷ +ø +þ +đ +ħ +ı +ł +ŋ +œ +ƒ +ɐ +ɑ +ɒ +ɔ +ɕ +ə +ɛ +ɡ +ɣ +ɨ +ɪ +ɫ +ɬ +ɯ +ɲ +ɴ +ɹ +ɾ +ʀ +ʁ +ʂ +ʃ +ʉ +ʊ +ʋ +ʌ +ʎ +ʐ +ʑ +ʒ +ʔ +ʰ +ʲ +ʳ +ʷ +ʸ +ʻ +ʼ +ʾ +ʿ +ˈ +ː +ˡ +ˢ +ˣ +ˤ +α +β +γ +δ +ε +ζ +η +θ +ι +κ +λ +μ +ν +ξ +ο +π +ρ +ς +σ +τ +υ +φ +χ +ψ +ω +а +б +в +г +д +е +ж +з +и +к +л +м +н +о +п +р +с +т +у +ф +х +ц +ч +ш +щ +ъ +ы +ь +э +ю +я +ђ +є +і +ј +љ +њ +ћ +ӏ +ա +բ +գ +դ +ե +թ +ի +լ +կ +հ +մ +յ +ն +ո +պ +ս +վ +տ +ր +ւ +ք +־ +א +ב +ג +ד +ה +ו +ז +ח +ט +י +ך +כ +ל +ם +מ +ן +נ +ס +ע +ף +פ +ץ +צ +ק +ר +ש +ת +، +ء +ا +ب +ة +ت +ث +ج +ح +خ +د +ذ +ر +ز +س +ش +ص +ض +ط +ظ +ع +غ +ـ +ف +ق +ك +ل +م +ن +ه +و +ى +ي +ٹ +پ +چ +ک +گ +ں +ھ +ہ +ی +ے +अ +आ +उ +ए +क +ख +ग +च +ज +ट +ड +ण +त +थ +द +ध +न +प +ब +भ +म +य +र +ल +व +श +ष +स +ह +ा +ि +ी +ो +। +॥ +ং +অ +আ +ই +উ +এ +ও +ক +খ +গ +চ +ছ +জ +ট +ড +ণ +ত +থ +দ +ধ +ন +প +ব +ভ +ম +য +র +ল +শ +ষ +স +হ +া +ি +ী +ে +க +ச +ட +த +ந +ன +ப +ம +ய +ர +ல +ள +வ +ா +ி +ு +ே +ை +ನ +ರ +ಾ +ක +ය +ර +ල +ව +ා +ก +ง +ต +ท +น +พ +ม +ย +ร +ล +ว +ส +อ +า +เ +་ +། +ག +ང +ད +ན +པ +བ +མ +འ +ར +ལ +ས +မ +ა +ბ +გ +დ +ე +ვ +თ +ი +კ +ლ +მ +ნ +ო +რ +ს +ტ +უ +ᄀ +ᄂ +ᄃ +ᄅ +ᄆ +ᄇ +ᄉ +ᄊ +ᄋ +ᄌ +ᄎ +ᄏ +ᄐ +ᄑ +ᄒ +ᅡ +ᅢ +ᅥ +ᅦ +ᅧ +ᅩ +ᅪ +ᅭ +ᅮ +ᅯ +ᅲ +ᅳ +ᅴ +ᅵ +ᆨ +ᆫ +ᆯ +ᆷ +ᆸ +ᆼ +ᴬ +ᴮ +ᴰ +ᴵ +ᴺ +ᵀ +ᵃ +ᵇ +ᵈ +ᵉ +ᵍ +ᵏ +ᵐ +ᵒ +ᵖ +ᵗ +ᵘ +ᵢ +ᵣ +ᵤ +ᵥ +ᶜ +ᶠ +‐ +‑ +‒ +– +— +― +‖ +‘ +’ +‚ +“ +” +„ +† +‡ +• +… +‰ +′ +″ +› +‿ +⁄ +⁰ +ⁱ +⁴ +⁵ +⁶ +⁷ +⁸ +⁹ +⁺ +⁻ +ⁿ +₀ +₁ +₂ +₃ +₄ +₅ +₆ +₇ +₈ +₉ +₊ +₍ +₎ +ₐ +ₑ +ₒ +ₓ +ₕ +ₖ +ₗ +ₘ +ₙ +ₚ +ₛ +ₜ +₤ +₩ +€ +₱ +₹ +ℓ +№ +ℝ +™ +⅓ +⅔ +← +↑ +→ +↓ +↔ +↦ +⇄ +⇌ +⇒ +∂ +∅ +∆ +∇ +∈ +− +∗ +∘ +√ +∞ +∧ +∨ +∩ +∪ +≈ +≡ +≤ +≥ +⊂ +⊆ +⊕ +⊗ +⋅ +─ +│ +■ +▪ +● +★ +☆ +☉ +♠ +♣ +♥ +♦ +♭ +♯ +⟨ +⟩ +ⱼ +⺩ +⺼ +⽥ +、 +。 +〈 +〉 +《 +》 +「 +」 +『 +』 +〜 +あ +い +う +え +お +か +き +く +け +こ +さ +し +す +せ +そ +た +ち +っ +つ +て +と +な +に +ぬ +ね +の +は +ひ +ふ +へ +ほ +ま +み +む +め +も +や +ゆ +よ +ら +り +る +れ +ろ +を +ん +ァ +ア +ィ +イ +ウ +ェ +エ +オ +カ +キ +ク +ケ +コ +サ +シ +ス +セ +タ +チ +ッ +ツ +テ +ト +ナ +ニ +ノ +ハ +ヒ +フ +ヘ +ホ +マ +ミ +ム +メ +モ +ャ +ュ +ョ +ラ +リ +ル +レ +ロ +ワ +ン +・ +ー +一 +三 +上 +下 +不 +世 +中 +主 +久 +之 +也 +事 +二 +五 +井 +京 +人 +亻 +仁 +介 +代 +仮 +伊 +会 +佐 +侍 +保 +信 +健 +元 +光 +八 +公 +内 +出 +分 +前 +劉 +力 +加 +勝 +北 +区 +十 +千 +南 +博 +原 +口 +古 +史 +司 +合 +吉 +同 +名 +和 +囗 +四 +国 +國 +土 +地 +坂 +城 +堂 +場 +士 +夏 +外 +大 +天 +太 +夫 +奈 +女 +子 +学 +宀 +宇 +安 +宗 +定 +宣 +宮 +家 +宿 +寺 +將 +小 +尚 +山 +岡 +島 +崎 +川 +州 +巿 +帝 +平 +年 +幸 +广 +弘 +張 +彳 +後 +御 +德 +心 +忄 +志 +忠 +愛 +成 +我 +戦 +戸 +手 +扌 +政 +文 +新 +方 +日 +明 +星 +春 +昭 +智 +曲 +書 +月 +有 +朝 +木 +本 +李 +村 +東 +松 +林 +森 +楊 +樹 +橋 +歌 +止 +正 +武 +比 +氏 +民 +水 +氵 +氷 +永 +江 +沢 +河 +治 +法 +海 +清 +漢 +瀬 +火 +版 +犬 +王 +生 +田 +男 +疒 +発 +白 +的 +皇 +目 +相 +省 +真 +石 +示 +社 +神 +福 +禾 +秀 +秋 +空 +立 +章 +竹 +糹 +美 +義 +耳 +良 +艹 +花 +英 +華 +葉 +藤 +行 +街 +西 +見 +訁 +語 +谷 +貝 +貴 +車 +軍 +辶 +道 +郎 +郡 +部 +都 +里 +野 +金 +鈴 +镇 +長 +門 +間 +阝 +阿 +陳 +陽 +雄 +青 +面 +風 +食 +香 +馬 +高 +龍 +龸 +fi +fl +! +( +) +, +- +. +/ +: +? +~ +the +of +and +in +to +was +he +is +as +for +on +with +that +it +his +by +at +from +her +##s +she +you +had +an +were +but +be +this +are +not +my +they +one +which +or +have +him +me +first +all +also +their +has +up +who +out +been +when +after +there +into +new +two +its +##a +time +would +no +what +about +said +we +over +then +other +so +more +##e +can +if +like +back +them +only +some +could +##i +where +just +##ing +during +before +##n +do +##o +made +school +through +than +now +years +most +world +may +between +down +well +three +##d +year +while +will +##ed +##r +##y +later +##t +city +under +around +did +such +being +used +state +people +part +know +against +your +many +second +university +both +national +##er +these +don +known +off +way +until +re +how +even +get +head +... +didn +##ly +team +american +because +de +##l +born +united +film +since +still +long +work +south +us +became +any +high +again +day +family +see +right +man +eyes +house +season +war +states +including +took +life +north +same +each +called +name +much +place +however +go +four +group +another +found +won +area +here +going +10 +away +series +left +home +music +best +make +hand +number +company +several +never +last +john +000 +very +album +take +end +good +too +following +released +game +played +little +began +district +##m +old +want +those +side +held +own +early +county +ll +league +use +west +##u +face +think +##es +2010 +government +##h +march +came +small +general +town +june +##on +line +based +something +##k +september +thought +looked +along +international +2011 +air +july +club +went +january +october +our +august +april +york +12 +few +2012 +2008 +east +show +member +college +2009 +father +public +##us +come +men +five +set +station +church +##c +next +former +november +room +party +located +december +2013 +age +got +2007 +##g +system +let +love +2006 +though +every +2014 +look +song +water +century +without +body +black +night +within +great +women +single +ve +building +large +population +river +named +band +white +started +##an +once +15 +20 +should +18 +2015 +service +top +built +british +open +death +king +moved +local +times +children +february +book +why +11 +door +need +president +order +final +road +wasn +although +due +major +died +village +third +knew +2016 +asked +turned +st +wanted +say +##p +together +received +main +son +served +different +##en +behind +himself +felt +members +power +football +law +voice +play +##in +near +park +history +30 +having +2005 +16 +##man +saw +mother +##al +army +point +front +help +english +street +art +late +hands +games +award +##ia +young +14 +put +published +country +division +across +told +13 +often +ever +french +london +center +six +red +2017 +led +days +include +light +25 +find +tell +among +species +really +according +central +half +2004 +form +original +gave +office +making +enough +lost +full +opened +must +included +live +given +german +player +run +business +woman +community +cup +might +million +land +2000 +court +development +17 +short +round +ii +km +seen +class +story +always +become +sure +research +almost +director +council +la +##2 +career +things +using +island +##z +couldn +car +##is +24 +close +force +##1 +better +free +support +control +field +students +2003 +education +married +##b +nothing +worked +others +record +big +inside +level +anything +continued +give +james +##3 +military +established +non +returned +feel +does +title +written +thing +feet +william +far +co +association +hard +already +2002 +##ra +championship +human +western +100 +##na +department +hall +role +various +production +21 +19 +heart +2001 +living +fire +version +##ers +##f +television +royal +##4 +produced +working +act +case +society +region +present +radio +period +looking +least +total +keep +england +wife +program +per +brother +mind +special +22 +##le +am +works +soon +##6 +political +george +services +taken +created +##7 +further +able +reached +david +union +joined +upon +done +important +social +information +either +##ic +##x +appeared +position +ground +lead +rock +dark +election +23 +board +france +hair +course +arms +site +police +girl +instead +real +sound +##v +words +moment +##te +someone +##8 +summer +project +announced +san +less +wrote +past +followed +##5 +blue +founded +al +finally +india +taking +records +america +##ne +1999 +design +considered +northern +god +stop +battle +toward +european +outside +described +track +today +playing +language +28 +call +26 +heard +professional +low +australia +miles +california +win +yet +green +##ie +trying +blood +##ton +southern +science +maybe +everything +match +square +27 +mouth +video +race +recorded +leave +above +##9 +daughter +points +space +1998 +museum +change +middle +common +##0 +move +tv +post +##ta +lake +seven +tried +elected +closed +ten +paul +minister +##th +months +start +chief +return +canada +person +sea +release +similar +modern +brought +rest +hit +formed +mr +##la +1997 +floor +event +doing +thomas +1996 +robert +care +killed +training +star +week +needed +turn +finished +railway +rather +news +health +sent +example +ran +term +michael +coming +currently +yes +forces +despite +gold +areas +50 +stage +fact +29 +dead +says +popular +2018 +originally +germany +probably +developed +result +pulled +friend +stood +money +running +mi +signed +word +songs +child +eventually +met +tour +average +teams +minutes +festival +current +deep +kind +1995 +decided +usually +eastern +seemed +##ness +episode +bed +added +table +indian +private +charles +route +available +idea +throughout +centre +addition +appointed +style +1994 +books +eight +construction +press +mean +wall +friends +remained +schools +study +##ch +##um +institute +oh +chinese +sometimes +events +possible +1992 +australian +type +brown +forward +talk +process +food +debut +seat +performance +committee +features +character +arts +herself +else +lot +strong +russian +range +hours +peter +arm +##da +morning +dr +sold +##ry +quickly +directed +1993 +guitar +china +##w +31 +list +##ma +performed +media +uk +players +smile +##rs +myself +40 +placed +coach +province +towards +wouldn +leading +whole +boy +official +designed +grand +census +##el +europe +attack +japanese +henry +1991 +##re +##os +cross +getting +alone +action +lower +network +wide +washington +japan +1990 +hospital +believe +changed +sister +##ar +hold +gone +sir +hadn +ship +##ka +studies +academy +shot +rights +below +base +bad +involved +kept +largest +##ist +bank +future +especially +beginning +mark +movement +section +female +magazine +plan +professor +lord +longer +##ian +sat +walked +hill +actually +civil +energy +model +families +size +thus +aircraft +completed +includes +data +captain +##or +fight +vocals +featured +richard +bridge +fourth +1989 +officer +stone +hear +##ism +means +medical +groups +management +self +lips +competition +entire +lived +technology +leaving +federal +tournament +bit +passed +hot +independent +awards +kingdom +mary +spent +fine +doesn +reported +##ling +jack +fall +raised +itself +stay +true +studio +1988 +sports +replaced +paris +systems +saint +leader +theatre +whose +market +capital +parents +spanish +canadian +earth +##ity +cut +degree +writing +bay +christian +awarded +natural +higher +bill +##as +coast +provided +previous +senior +ft +valley +organization +stopped +onto +countries +parts +conference +queen +security +interest +saying +allowed +master +earlier +phone +matter +smith +winning +try +happened +moving +campaign +los +##ley +breath +nearly +mid +1987 +certain +girls +date +italian +african +standing +fell +artist +##ted +shows +deal +mine +industry +1986 +##ng +everyone +republic +provide +collection +library +student +##ville +primary +owned +older +via +heavy +1st +makes +##able +attention +anyone +africa +##ri +stated +length +ended +fingers +command +staff +skin +foreign +opening +governor +okay +medal +kill +sun +cover +job +1985 +introduced +chest +hell +feeling +##ies +success +meet +reason +standard +meeting +novel +1984 +trade +source +buildings +##land +rose +guy +goal +##ur +chapter +native +husband +previously +unit +limited +entered +weeks +producer +operations +mountain +takes +covered +forced +related +roman +complete +successful +key +texas +cold +##ya +channel +1980 +traditional +films +dance +clear +approximately +500 +nine +van +prince +question +active +tracks +ireland +regional +silver +author +personal +sense +operation +##ine +economic +1983 +holding +twenty +isbn +additional +speed +hour +edition +regular +historic +places +whom +shook +movie +km² +secretary +prior +report +chicago +read +foundation +view +engine +scored +1982 +units +ask +airport +property +ready +immediately +lady +month +listed +contract +##de +manager +themselves +lines +##ki +navy +writer +meant +##ts +runs +##ro +practice +championships +singer +glass +commission +required +forest +starting +culture +generally +giving +access +attended +test +couple +stand +catholic +martin +caught +executive +##less +eye +##ey +thinking +chair +quite +shoulder +1979 +hope +decision +plays +defeated +municipality +whether +structure +offered +slowly +pain +ice +direction +##ion +paper +mission +1981 +mostly +200 +noted +individual +managed +nature +lives +plant +##ha +helped +except +studied +computer +figure +relationship +issue +significant +loss +die +smiled +gun +ago +highest +1972 +##am +male +bring +goals +mexico +problem +distance +commercial +completely +location +annual +famous +drive +1976 +neck +1978 +surface +caused +italy +understand +greek +highway +wrong +hotel +comes +appearance +joseph +double +issues +musical +companies +castle +income +review +assembly +bass +initially +parliament +artists +experience +1974 +particular +walk +foot +engineering +talking +window +dropped +##ter +miss +baby +boys +break +1975 +stars +edge +remember +policy +carried +train +stadium +bar +sex +angeles +evidence +##ge +becoming +assistant +soviet +1977 +upper +step +wing +1970 +youth +financial +reach +##ll +actor +numerous +##se +##st +nodded +arrived +##ation +minute +##nt +believed +sorry +complex +beautiful +victory +associated +temple +1968 +1973 +chance +perhaps +metal +##son +1945 +bishop +##et +lee +launched +particularly +tree +le +retired +subject +prize +contains +yeah +theory +empire +##ce +suddenly +waiting +trust +recording +##to +happy +terms +camp +champion +1971 +religious +pass +zealand +names +2nd +port +ancient +tom +corner +represented +watch +legal +anti +justice +cause +watched +brothers +45 +material +changes +simply +response +louis +fast +##ting +answer +60 +historical +1969 +stories +straight +create +feature +increased +rate +administration +virginia +el +activities +cultural +overall +winner +programs +basketball +legs +guard +beyond +cast +doctor +mm +flight +results +remains +cost +effect +winter +##ble +larger +islands +problems +chairman +grew +commander +isn +1967 +pay +failed +selected +hurt +fort +box +regiment +majority +journal +35 +edward +plans +##ke +##ni +shown +pretty +irish +characters +directly +scene +likely +operated +allow +spring +##j +junior +matches +looks +mike +houses +fellow +##tion +beach +marriage +##ham +##ive +rules +oil +65 +florida +expected +nearby +congress +sam +peace +recent +iii +wait +subsequently +cell +##do +variety +serving +agreed +please +poor +joe +pacific +attempt +wood +democratic +piece +prime +##ca +rural +mile +touch +appears +township +1964 +1966 +soldiers +##men +##ized +1965 +pennsylvania +closer +fighting +claimed +score +jones +physical +editor +##ous +filled +genus +specific +sitting +super +mom +##va +therefore +supported +status +fear +cases +store +meaning +wales +minor +spain +tower +focus +vice +frank +follow +parish +separate +golden +horse +fifth +remaining +branch +32 +presented +stared +##id +uses +secret +forms +##co +baseball +exactly +##ck +choice +note +discovered +travel +composed +truth +russia +ball +color +kiss +dad +wind +continue +ring +referred +numbers +digital +greater +##ns +metres +slightly +direct +increase +1960 +responsible +crew +rule +trees +troops +##no +broke +goes +individuals +hundred +weight +creek +sleep +memory +defense +provides +ordered +code +value +jewish +windows +1944 +safe +judge +whatever +corps +realized +growing +pre +##ga +cities +alexander +gaze +lies +spread +scott +letter +showed +situation +mayor +transport +watching +workers +extended +##li +expression +normal +##ment +chart +multiple +border +##ba +host +##ner +daily +mrs +walls +piano +##ko +heat +cannot +##ate +earned +products +drama +era +authority +seasons +join +grade +##io +sign +difficult +machine +1963 +territory +mainly +##wood +stations +squadron +1962 +stepped +iron +19th +##led +serve +appear +sky +speak +broken +charge +knowledge +kilometres +removed +ships +article +campus +simple +##ty +pushed +britain +##ve +leaves +recently +cd +soft +boston +latter +easy +acquired +poland +##sa +quality +officers +presence +planned +nations +mass +broadcast +jean +share +image +influence +wild +offer +emperor +electric +reading +headed +ability +promoted +yellow +ministry +1942 +throat +smaller +politician +##by +latin +spoke +cars +williams +males +lack +pop +80 +##ier +acting +seeing +consists +##ti +estate +1961 +pressure +johnson +newspaper +jr +chris +olympics +online +conditions +beat +elements +walking +vote +##field +needs +carolina +text +featuring +global +block +shirt +levels +francisco +purpose +females +et +dutch +duke +ahead +gas +twice +safety +serious +turning +highly +lieutenant +firm +maria +amount +mixed +daniel +proposed +perfect +agreement +affairs +3rd +seconds +contemporary +paid +1943 +prison +save +kitchen +label +administrative +intended +constructed +academic +nice +teacher +races +1956 +formerly +corporation +ben +nation +issued +shut +1958 +drums +housing +victoria +seems +opera +1959 +graduated +function +von +mentioned +picked +build +recognized +shortly +protection +picture +notable +exchange +elections +1980s +loved +percent +racing +fish +elizabeth +garden +volume +hockey +1941 +beside +settled +##ford +1940 +competed +replied +drew +1948 +actress +marine +scotland +steel +glanced +farm +steve +1957 +risk +tonight +positive +magic +singles +effects +gray +screen +dog +##ja +residents +bus +sides +none +secondary +literature +polish +destroyed +flying +founder +households +1939 +lay +reserve +usa +gallery +##ler +1946 +industrial +younger +approach +appearances +urban +ones +1950 +finish +avenue +powerful +fully +growth +page +honor +jersey +projects +advanced +revealed +basic +90 +infantry +pair +equipment +visit +33 +evening +search +grant +effort +solo +treatment +buried +republican +primarily +bottom +owner +1970s +israel +gives +jim +dream +bob +remain +spot +70 +notes +produce +champions +contact +ed +soul +accepted +ways +del +##ally +losing +split +price +capacity +basis +trial +questions +##ina +1955 +20th +guess +officially +memorial +naval +initial +##ization +whispered +median +engineer +##ful +sydney +##go +columbia +strength +300 +1952 +tears +senate +00 +card +asian +agent +1947 +software +44 +draw +warm +supposed +com +pro +##il +transferred +leaned +##at +candidate +escape +mountains +asia +potential +activity +entertainment +seem +traffic +jackson +murder +36 +slow +product +orchestra +haven +agency +bbc +taught +website +comedy +unable +storm +planning +albums +rugby +environment +scientific +grabbed +protect +##hi +boat +typically +1954 +1953 +damage +principal +divided +dedicated +mount +ohio +##berg +pick +fought +driver +##der +empty +shoulders +sort +thank +berlin +prominent +account +freedom +necessary +efforts +alex +headquarters +follows +alongside +des +simon +andrew +suggested +operating +learning +steps +1949 +sweet +technical +begin +easily +34 +teeth +speaking +settlement +scale +##sh +renamed +ray +max +enemy +semi +joint +compared +##rd +scottish +leadership +analysis +offers +georgia +pieces +captured +animal +deputy +guest +organized +##lin +tony +combined +method +challenge +1960s +huge +wants +battalion +sons +rise +crime +types +facilities +telling +path +1951 +platform +sit +1990s +##lo +tells +assigned +rich +pull +##ot +commonly +alive +##za +letters +concept +conducted +wearing +happen +bought +becomes +holy +gets +ocean +defeat +languages +purchased +coffee +occurred +titled +##q +declared +applied +sciences +concert +sounds +jazz +brain +##me +painting +fleet +tax +nick +##ius +michigan +count +animals +leaders +episodes +##line +content +##den +birth +##it +clubs +64 +palace +critical +refused +fair +leg +laughed +returning +surrounding +participated +formation +lifted +pointed +connected +rome +medicine +laid +taylor +santa +powers +adam +tall +shared +focused +knowing +yards +entrance +falls +##wa +calling +##ad +sources +chosen +beneath +resources +yard +##ite +nominated +silence +zone +defined +##que +gained +thirty +38 +bodies +moon +##ard +adopted +christmas +widely +register +apart +iran +premier +serves +du +unknown +parties +##les +generation +##ff +continues +quick +fields +brigade +quiet +teaching +clothes +impact +weapons +partner +flat +theater +supreme +1938 +37 +relations +##tor +plants +suffered +1936 +wilson +kids +begins +##age +1918 +seats +armed +internet +models +worth +laws +400 +communities +classes +background +knows +thanks +quarter +reaching +humans +carry +killing +format +kong +hong +setting +75 +architecture +disease +railroad +inc +possibly +wish +arthur +thoughts +harry +doors +density +##di +crowd +illinois +stomach +tone +unique +reports +anyway +##ir +liberal +der +vehicle +thick +dry +drug +faced +largely +facility +theme +holds +creation +strange +colonel +##mi +revolution +bell +politics +turns +silent +rail +relief +independence +combat +shape +write +determined +sales +learned +4th +finger +oxford +providing +1937 +heritage +fiction +situated +designated +allowing +distribution +hosted +##est +sight +interview +estimated +reduced +##ria +toronto +footballer +keeping +guys +damn +claim +motion +sport +sixth +stayed +##ze +en +rear +receive +handed +twelve +dress +audience +granted +brazil +##well +spirit +##ated +noticed +etc +olympic +representative +eric +tight +trouble +reviews +drink +vampire +missing +roles +ranked +newly +household +finals +wave +critics +##ee +phase +massachusetts +pilot +unlike +philadelphia +bright +guns +crown +organizations +roof +42 +respectively +clearly +tongue +marked +circle +fox +korea +bronze +brian +expanded +sexual +supply +yourself +inspired +labour +fc +##ah +reference +vision +draft +connection +brand +reasons +1935 +classic +driving +trip +jesus +cells +entry +1920 +neither +trail +claims +atlantic +orders +labor +nose +afraid +identified +intelligence +calls +cancer +attacked +passing +stephen +positions +imperial +grey +jason +39 +sunday +48 +swedish +avoid +extra +uncle +message +covers +allows +surprise +materials +fame +hunter +##ji +1930 +citizens +figures +davis +environmental +confirmed +shit +titles +di +performing +difference +acts +attacks +##ov +existing +votes +opportunity +nor +shop +entirely +trains +opposite +pakistan +##pa +develop +resulted +representatives +actions +reality +pressed +##ish +barely +wine +conversation +faculty +northwest +ends +documentary +nuclear +stock +grace +sets +eat +alternative +##ps +bag +resulting +creating +surprised +cemetery +1919 +drop +finding +sarah +cricket +streets +tradition +ride +1933 +exhibition +target +ear +explained +rain +composer +injury +apartment +municipal +educational +occupied +netherlands +clean +billion +constitution +learn +1914 +maximum +classical +francis +lose +opposition +jose +ontario +bear +core +hills +rolled +ending +drawn +permanent +fun +##tes +##lla +lewis +sites +chamber +ryan +##way +scoring +height +1934 +##house +lyrics +staring +55 +officials +1917 +snow +oldest +##tic +orange +##ger +qualified +interior +apparently +succeeded +thousand +dinner +lights +existence +fans +heavily +41 +greatest +conservative +send +bowl +plus +enter +catch +##un +economy +duty +1929 +speech +authorities +princess +performances +versions +shall +graduate +pictures +effective +remembered +poetry +desk +crossed +starring +starts +passenger +sharp +##ant +acres +ass +weather +falling +rank +fund +supporting +check +adult +publishing +heads +cm +southeast +lane +##burg +application +bc +##ura +les +condition +transfer +prevent +display +ex +regions +earl +federation +cool +relatively +answered +besides +1928 +obtained +portion +##town +mix +##ding +reaction +liked +dean +express +peak +1932 +##tte +counter +religion +chain +rare +miller +convention +aid +lie +vehicles +mobile +perform +squad +wonder +lying +crazy +sword +##ping +attempted +centuries +weren +philosophy +category +##ize +anna +interested +47 +sweden +wolf +frequently +abandoned +kg +literary +alliance +task +entitled +##ay +threw +promotion +factory +tiny +soccer +visited +matt +fm +achieved +52 +defence +internal +persian +43 +methods +##ging +arrested +otherwise +cambridge +programming +villages +elementary +districts +rooms +criminal +conflict +worry +trained +1931 +attempts +waited +signal +bird +truck +subsequent +programme +##ol +ad +49 +communist +details +faith +sector +patrick +carrying +laugh +##ss +controlled +korean +showing +origin +fuel +evil +1927 +##ent +brief +identity +darkness +address +pool +missed +publication +web +planet +ian +anne +wings +invited +##tt +briefly +standards +kissed +##be +ideas +climate +causing +walter +worse +albert +articles +winners +desire +aged +northeast +dangerous +gate +doubt +1922 +wooden +multi +##ky +poet +rising +funding +46 +communications +communication +violence +copies +prepared +ford +investigation +skills +1924 +pulling +electronic +##ak +##ial +##han +containing +ultimately +offices +singing +understanding +restaurant +tomorrow +fashion +christ +ward +da +pope +stands +5th +flow +studios +aired +commissioned +contained +exist +fresh +americans +##per +wrestling +approved +kid +employed +respect +suit +1925 +angel +asking +increasing +frame +angry +selling +1950s +thin +finds +##nd +temperature +statement +ali +explain +inhabitants +towns +extensive +narrow +51 +jane +flowers +images +promise +somewhere +object +fly +closely +##ls +1912 +bureau +cape +1926 +weekly +presidential +legislative +1921 +##ai +##au +launch +founding +##ny +978 +##ring +artillery +strike +un +institutions +roll +writers +landing +chose +kevin +anymore +pp +##ut +attorney +fit +dan +billboard +receiving +agricultural +breaking +sought +dave +admitted +lands +mexican +##bury +charlie +specifically +hole +iv +howard +credit +moscow +roads +accident +1923 +proved +wear +struck +hey +guards +stuff +slid +expansion +1915 +cat +anthony +##kin +melbourne +opposed +sub +southwest +architect +failure +plane +1916 +##ron +map +camera +tank +listen +regarding +wet +introduction +metropolitan +link +ep +fighter +inch +grown +gene +anger +fixed +buy +dvd +khan +domestic +worldwide +chapel +mill +functions +examples +##head +developing +1910 +turkey +hits +pocket +antonio +papers +grow +unless +circuit +18th +concerned +attached +journalist +selection +journey +converted +provincial +painted +hearing +aren +bands +negative +aside +wondered +knight +lap +survey +ma +##ow +noise +billy +##ium +shooting +guide +bedroom +priest +resistance +motor +homes +sounded +giant +##mer +150 +scenes +equal +comic +patients +hidden +solid +actual +bringing +afternoon +touched +funds +wedding +consisted +marie +canal +sr +kim +treaty +turkish +recognition +residence +cathedral +broad +knees +incident +shaped +fired +norwegian +handle +cheek +contest +represent +##pe +representing +beauty +##sen +birds +advantage +emergency +wrapped +drawing +notice +pink +broadcasting +##ong +somehow +bachelor +seventh +collected +registered +establishment +alan +assumed +chemical +personnel +roger +retirement +jeff +portuguese +wore +tied +device +threat +progress +advance +##ised +banks +hired +manchester +nfl +teachers +structures +forever +##bo +tennis +helping +saturday +sale +applications +junction +hip +incorporated +neighborhood +dressed +ceremony +##ds +influenced +hers +visual +stairs +decades +inner +kansas +hung +hoped +gain +scheduled +downtown +engaged +austria +clock +norway +certainly +pale +protected +1913 +victor +employees +plate +putting +surrounded +##ists +finishing +blues +tropical +##ries +minnesota +consider +philippines +accept +54 +retrieved +1900 +concern +anderson +properties +institution +gordon +successfully +vietnam +##dy +backing +outstanding +muslim +crossing +folk +producing +usual +demand +occurs +observed +lawyer +educated +##ana +kelly +string +pleasure +budget +items +quietly +colorado +philip +typical +##worth +derived +600 +survived +asks +mental +##ide +56 +jake +jews +distinguished +ltd +1911 +sri +extremely +53 +athletic +loud +thousands +worried +shadow +transportation +horses +weapon +arena +importance +users +tim +objects +contributed +dragon +douglas +aware +senator +johnny +jordan +sisters +engines +flag +investment +samuel +shock +capable +clark +row +wheel +refers +session +familiar +biggest +wins +hate +maintained +drove +hamilton +request +expressed +injured +underground +churches +walker +wars +tunnel +passes +stupid +agriculture +softly +cabinet +regarded +joining +indiana +##ea +##ms +push +dates +spend +behavior +woods +protein +gently +chase +morgan +mention +burning +wake +combination +occur +mirror +leads +jimmy +indeed +impossible +singapore +paintings +covering +##nes +soldier +locations +attendance +sell +historian +wisconsin +invasion +argued +painter +diego +changing +egypt +##don +experienced +inches +##ku +missouri +vol +grounds +spoken +switzerland +##gan +reform +rolling +ha +forget +massive +resigned +burned +allen +tennessee +locked +values +improved +##mo +wounded +universe +sick +dating +facing +pack +purchase +user +##pur +moments +##ul +merged +anniversary +1908 +coal +brick +understood +causes +dynasty +queensland +establish +stores +crisis +promote +hoping +views +cards +referee +extension +##si +raise +arizona +improve +colonial +formal +charged +##rt +palm +lucky +hide +rescue +faces +95 +feelings +candidates +juan +##ell +goods +6th +courses +weekend +59 +luke +cash +fallen +##om +delivered +affected +installed +carefully +tries +swiss +hollywood +costs +lincoln +responsibility +##he +shore +file +proper +normally +maryland +assistance +jump +constant +offering +friendly +waters +persons +realize +contain +trophy +800 +partnership +factor +58 +musicians +cry +bound +oregon +indicated +hero +houston +medium +##ure +consisting +somewhat +##ara +57 +cycle +##che +beer +moore +frederick +gotten +eleven +worst +weak +approached +arranged +chin +loan +universal +bond +fifteen +pattern +disappeared +##ney +translated +##zed +lip +arab +capture +interests +insurance +##chi +shifted +cave +prix +warning +sections +courts +coat +plot +smell +feed +golf +favorite +maintain +knife +vs +voted +degrees +finance +quebec +opinion +translation +manner +ruled +operate +productions +choose +musician +discovery +confused +tired +separated +stream +techniques +committed +attend +ranking +kings +throw +passengers +measure +horror +fan +mining +sand +danger +salt +calm +decade +dam +require +runner +##ik +rush +associate +greece +##ker +rivers +consecutive +matthew +##ski +sighed +sq +documents +steam +edited +closing +tie +accused +1905 +##ini +islamic +distributed +directors +organisation +bruce +7th +breathing +mad +lit +arrival +concrete +taste +08 +composition +shaking +faster +amateur +adjacent +stating +1906 +twin +flew +##ran +tokyo +publications +##tone +obviously +ridge +storage +1907 +carl +pages +concluded +desert +driven +universities +ages +terminal +sequence +borough +250 +constituency +creative +cousin +economics +dreams +margaret +notably +reduce +montreal +mode +17th +ears +saved +jan +vocal +##ica +1909 +andy +##jo +riding +roughly +threatened +##ise +meters +meanwhile +landed +compete +repeated +grass +czech +regularly +charges +tea +sudden +appeal +##ung +solution +describes +pierre +classification +glad +parking +##ning +belt +physics +99 +rachel +add +hungarian +participate +expedition +damaged +gift +childhood +85 +fifty +##red +mathematics +jumped +letting +defensive +mph +##ux +##gh +testing +##hip +hundreds +shoot +owners +matters +smoke +israeli +kentucky +dancing +mounted +grandfather +emma +designs +profit +argentina +##gs +truly +li +lawrence +cole +begun +detroit +willing +branches +smiling +decide +miami +enjoyed +recordings +##dale +poverty +ethnic +gay +##bi +gary +arabic +09 +accompanied +##one +##ons +fishing +determine +residential +acid +##ary +alice +returns +starred +mail +##ang +jonathan +strategy +##ue +net +forty +cook +businesses +equivalent +commonwealth +distinct +ill +##cy +seriously +##ors +##ped +shift +harris +replace +rio +imagine +formula +ensure +##ber +additionally +scheme +conservation +occasionally +purposes +feels +favor +##and +##ore +1930s +contrast +hanging +hunt +movies +1904 +instruments +victims +danish +christopher +busy +demon +sugar +earliest +colony +studying +balance +duties +##ks +belgium +slipped +carter +05 +visible +stages +iraq +fifa +##im +commune +forming +zero +07 +continuing +talked +counties +legend +bathroom +option +tail +clay +daughters +afterwards +severe +jaw +visitors +##ded +devices +aviation +russell +kate +##vi +entering +subjects +##ino +temporary +swimming +forth +smooth +ghost +audio +bush +operates +rocks +movements +signs +eddie +##tz +ann +voices +honorary +06 +memories +dallas +pure +measures +racial +promised +66 +harvard +ceo +16th +parliamentary +indicate +benefit +flesh +dublin +louisiana +1902 +1901 +patient +sleeping +1903 +membership +coastal +medieval +wanting +element +scholars +rice +62 +limit +survive +makeup +rating +definitely +collaboration +obvious +##tan +boss +ms +baron +birthday +linked +soil +diocese +##lan +ncaa +##mann +offensive +shell +shouldn +waist +##tus +plain +ross +organ +resolution +manufacturing +adding +relative +kennedy +98 +whilst +moth +marketing +gardens +crash +72 +heading +partners +credited +carlos +moves +cable +##zi +marshall +##out +depending +bottle +represents +rejected +responded +existed +04 +jobs +denmark +lock +##ating +treated +graham +routes +talent +commissioner +drugs +secure +tests +reign +restored +photography +##gi +contributions +oklahoma +designer +disc +grin +seattle +robin +paused +atlanta +unusual +##gate +praised +las +laughing +satellite +hungary +visiting +##sky +interesting +factors +deck +poems +norman +##water +stuck +speaker +rifle +domain +premiered +##her +dc +comics +actors +01 +reputation +eliminated +8th +ceiling +prisoners +script +##nce +leather +austin +mississippi +rapidly +admiral +parallel +charlotte +guilty +tools +gender +divisions +fruit +##bs +laboratory +nelson +fantasy +marry +rapid +aunt +tribe +requirements +aspects +suicide +amongst +adams +bone +ukraine +abc +kick +sees +edinburgh +clothing +column +rough +gods +hunting +broadway +gathered +concerns +##ek +spending +ty +12th +snapped +requires +solar +bones +cavalry +##tta +iowa +drinking +waste +index +franklin +charity +thompson +stewart +tip +flash +landscape +friday +enjoy +singh +poem +listening +##back +eighth +fred +differences +adapted +bomb +ukrainian +surgery +corporate +masters +anywhere +##more +waves +odd +sean +portugal +orleans +dick +debate +kent +eating +puerto +cleared +96 +expect +cinema +97 +guitarist +blocks +electrical +agree +involving +depth +dying +panel +struggle +##ged +peninsula +adults +novels +emerged +vienna +metro +debuted +shoes +tamil +songwriter +meets +prove +beating +instance +heaven +scared +sending +marks +artistic +passage +superior +03 +significantly +shopping +##tive +retained +##izing +malaysia +technique +cheeks +##ola +warren +maintenance +destroy +extreme +allied +120 +appearing +##yn +fill +advice +alabama +qualifying +policies +cleveland +hat +battery +smart +authors +10th +soundtrack +acted +dated +lb +glance +equipped +coalition +funny +outer +ambassador +roy +possibility +couples +campbell +dna +loose +ethan +supplies +1898 +gonna +88 +monster +##res +shake +agents +frequency +springs +dogs +practices +61 +gang +plastic +easier +suggests +gulf +blade +exposed +colors +industries +markets +pan +nervous +electoral +charts +legislation +ownership +##idae +mac +appointment +shield +copy +assault +socialist +abbey +monument +license +throne +employment +jay +93 +replacement +charter +cloud +powered +suffering +accounts +oak +connecticut +strongly +wright +colour +crystal +13th +context +welsh +networks +voiced +gabriel +jerry +##cing +forehead +mp +##ens +manage +schedule +totally +remix +##ii +forests +occupation +print +nicholas +brazilian +strategic +vampires +engineers +76 +roots +seek +correct +instrumental +und +alfred +backed +hop +##des +stanley +robinson +traveled +wayne +welcome +austrian +achieve +67 +exit +rates +1899 +strip +whereas +##cs +sing +deeply +adventure +bobby +rick +jamie +careful +components +cap +useful +personality +knee +##shi +pushing +hosts +02 +protest +ca +ottoman +symphony +##sis +63 +boundary +1890 +processes +considering +considerable +tons +##work +##ft +##nia +cooper +trading +dear +conduct +91 +illegal +apple +revolutionary +holiday +definition +harder +##van +jacob +circumstances +destruction +##lle +popularity +grip +classified +liverpool +donald +baltimore +flows +seeking +honour +approval +92 +mechanical +till +happening +statue +critic +increasingly +immediate +describe +commerce +stare +##ster +indonesia +meat +rounds +boats +baker +orthodox +depression +formally +worn +naked +claire +muttered +sentence +11th +emily +document +77 +criticism +wished +vessel +spiritual +bent +virgin +parker +minimum +murray +lunch +danny +printed +compilation +keyboards +false +blow +belonged +68 +raising +78 +cutting +##board +pittsburgh +##up +9th +shadows +81 +hated +indigenous +jon +15th +barry +scholar +ah +##zer +oliver +##gy +stick +susan +meetings +attracted +spell +romantic +##ver +ye +1895 +photo +demanded +customers +##ac +1896 +logan +revival +keys +modified +commanded +jeans +##ious +upset +raw +phil +detective +hiding +resident +vincent +##bly +experiences +diamond +defeating +coverage +lucas +external +parks +franchise +helen +bible +successor +percussion +celebrated +il +lift +profile +clan +romania +##ied +mills +##su +nobody +achievement +shrugged +fault +1897 +rhythm +initiative +breakfast +carbon +700 +69 +lasted +violent +74 +wound +ken +killer +gradually +filmed +°c +dollars +processing +94 +remove +criticized +guests +sang +chemistry +##vin +legislature +disney +##bridge +uniform +escaped +integrated +proposal +purple +denied +liquid +karl +influential +morris +nights +stones +intense +experimental +twisted +71 +84 +##ld +pace +nazi +mitchell +ny +blind +reporter +newspapers +14th +centers +burn +basin +forgotten +surviving +filed +collections +monastery +losses +manual +couch +description +appropriate +merely +tag +missions +sebastian +restoration +replacing +triple +73 +elder +julia +warriors +benjamin +julian +convinced +stronger +amazing +declined +versus +merchant +happens +output +finland +bare +barbara +absence +ignored +dawn +injuries +##port +producers +##ram +82 +luis +##ities +kw +admit +expensive +electricity +nba +exception +symbol +##ving +ladies +shower +sheriff +characteristics +##je +aimed +button +ratio +effectively +summit +angle +jury +bears +foster +vessels +pants +executed +evans +dozen +advertising +kicked +patrol +1889 +competitions +lifetime +principles +athletics +##logy +birmingham +sponsored +89 +rob +nomination +1893 +acoustic +##sm +creature +longest +##tra +credits +harbor +dust +josh +##so +territories +milk +infrastructure +completion +thailand +indians +leon +archbishop +##sy +assist +pitch +blake +arrangement +girlfriend +serbian +operational +hence +sad +scent +fur +dj +sessions +hp +refer +rarely +##ora +exists +1892 +##ten +scientists +dirty +penalty +burst +portrait +seed +79 +pole +limits +rival +1894 +stable +alpha +grave +constitutional +alcohol +arrest +flower +mystery +devil +architectural +relationships +greatly +habitat +##istic +larry +progressive +remote +cotton +##ics +##ok +preserved +reaches +##ming +cited +86 +vast +scholarship +decisions +cbs +joy +teach +1885 +editions +knocked +eve +searching +partly +participation +gap +animated +fate +excellent +##ett +na +87 +alternate +saints +youngest +##ily +climbed +##ita +##tors +suggest +##ct +discussion +staying +choir +lakes +jacket +revenue +nevertheless +peaked +instrument +wondering +annually +managing +neil +1891 +signing +terry +##ice +apply +clinical +brooklyn +aim +catherine +fuck +farmers +figured +ninth +pride +hugh +evolution +ordinary +involvement +comfortable +shouted +tech +encouraged +taiwan +representation +sharing +##lia +##em +panic +exact +cargo +competing +fat +cried +83 +1920s +occasions +pa +cabin +borders +utah +marcus +##isation +badly +muscles +##ance +victorian +transition +warner +bet +permission +##rin +slave +terrible +similarly +shares +seth +uefa +possession +medals +benefits +colleges +lowered +perfectly +mall +transit +##ye +##kar +publisher +##ened +harrison +deaths +elevation +##ae +asleep +machines +sigh +ash +hardly +argument +occasion +parent +leo +decline +1888 +contribution +##ua +concentration +1000 +opportunities +hispanic +guardian +extent +emotions +hips +mason +volumes +bloody +controversy +diameter +steady +mistake +phoenix +identify +violin +##sk +departure +richmond +spin +funeral +enemies +1864 +gear +literally +connor +random +sergeant +grab +confusion +1865 +transmission +informed +op +leaning +sacred +suspended +thinks +gates +portland +luck +agencies +yours +hull +expert +muscle +layer +practical +sculpture +jerusalem +latest +lloyd +statistics +deeper +recommended +warrior +arkansas +mess +supports +greg +eagle +1880 +recovered +rated +concerts +rushed +##ano +stops +eggs +files +premiere +keith +##vo +delhi +turner +pit +affair +belief +paint +##zing +mate +##ach +##ev +victim +##ology +withdrew +bonus +styles +fled +##ud +glasgow +technologies +funded +nbc +adaptation +##ata +portrayed +cooperation +supporters +judges +bernard +justin +hallway +ralph +##ick +graduating +controversial +distant +continental +spider +bite +##ho +recognize +intention +mixing +##ese +egyptian +bow +tourism +suppose +claiming +tiger +dominated +participants +vi +##ru +nurse +partially +tape +##rum +psychology +##rn +essential +touring +duo +voting +civilian +emotional +channels +##king +apparent +hebrew +1887 +tommy +carrier +intersection +beast +hudson +##gar +##zo +lab +nova +bench +discuss +costa +##ered +detailed +behalf +drivers +unfortunately +obtain +##lis +rocky +##dae +siege +friendship +honey +##rian +1861 +amy +hang +posted +governments +collins +respond +wildlife +preferred +operator +##po +laura +pregnant +videos +dennis +suspected +boots +instantly +weird +automatic +businessman +alleged +placing +throwing +ph +mood +1862 +perry +venue +jet +remainder +##lli +##ci +passion +biological +boyfriend +1863 +dirt +buffalo +ron +segment +fa +abuse +##era +genre +thrown +stroke +colored +stress +exercise +displayed +##gen +struggled +##tti +abroad +dramatic +wonderful +thereafter +madrid +component +widespread +##sed +tale +citizen +todd +monday +1886 +vancouver +overseas +forcing +crying +descent +##ris +discussed +substantial +ranks +regime +1870 +provinces +switch +drum +zane +ted +tribes +proof +lp +cream +researchers +volunteer +manor +silk +milan +donated +allies +venture +principle +delivery +enterprise +##ves +##ans +bars +traditionally +witch +reminded +copper +##uk +pete +inter +links +colin +grinned +elsewhere +competitive +frequent +##oy +scream +##hu +tension +texts +submarine +finnish +defending +defend +pat +detail +1884 +affiliated +stuart +themes +villa +periods +tool +belgian +ruling +crimes +answers +folded +licensed +resort +demolished +hans +lucy +1881 +lion +traded +photographs +writes +craig +##fa +trials +generated +beth +noble +debt +percentage +yorkshire +erected +ss +viewed +grades +confidence +ceased +islam +telephone +retail +##ible +chile +m² +roberts +sixteen +##ich +commented +hampshire +innocent +dual +pounds +checked +regulations +afghanistan +sung +rico +liberty +assets +bigger +options +angels +relegated +tribute +wells +attending +leaf +##yan +butler +romanian +forum +monthly +lisa +patterns +gmina +##tory +madison +hurricane +rev +##ians +bristol +##ula +elite +valuable +disaster +democracy +awareness +germans +freyja +##ins +loop +absolutely +paying +populations +maine +sole +prayer +spencer +releases +doorway +bull +##ani +lover +midnight +conclusion +##sson +thirteen +lily +mediterranean +##lt +nhl +proud +sample +##hill +drummer +guinea +##ova +murphy +climb +##ston +instant +attributed +horn +ain +railways +steven +##ao +autumn +ferry +opponent +root +traveling +secured +corridor +stretched +tales +sheet +trinity +cattle +helps +indicates +manhattan +murdered +fitted +1882 +gentle +grandmother +mines +shocked +vegas +produces +##light +caribbean +##ou +belong +continuous +desperate +drunk +historically +trio +waved +raf +dealing +nathan +bat +murmured +interrupted +residing +scientist +pioneer +harold +aaron +##net +delta +attempting +minority +mini +believes +chorus +tend +lots +eyed +indoor +load +shots +updated +jail +##llo +concerning +connecting +wealth +##ved +slaves +arrive +rangers +sufficient +rebuilt +##wick +cardinal +flood +muhammad +whenever +relation +runners +moral +repair +viewers +arriving +revenge +punk +assisted +bath +fairly +breathe +lists +innings +illustrated +whisper +nearest +voters +clinton +ties +ultimate +screamed +beijing +lions +andre +fictional +gathering +comfort +radar +suitable +dismissed +hms +ban +pine +wrist +atmosphere +voivodeship +bid +timber +##ned +##nan +giants +##ane +cameron +recovery +uss +identical +categories +switched +serbia +laughter +noah +ensemble +therapy +peoples +touching +##off +locally +pearl +platforms +everywhere +ballet +tables +lanka +herbert +outdoor +toured +derek +1883 +spaces +contested +swept +1878 +exclusive +slight +connections +##dra +winds +prisoner +collective +bangladesh +tube +publicly +wealthy +thai +##ys +isolated +select +##ric +insisted +pen +fortune +ticket +spotted +reportedly +animation +enforcement +tanks +110 +decides +wider +lowest +owen +##time +nod +hitting +##hn +gregory +furthermore +magazines +fighters +solutions +##ery +pointing +requested +peru +reed +chancellor +knights +mask +worker +eldest +flames +reduction +1860 +volunteers +##tis +reporting +##hl +wire +advisory +endemic +origins +settlers +pursue +knock +consumer +1876 +eu +compound +creatures +mansion +sentenced +ivan +deployed +guitars +frowned +involves +mechanism +kilometers +perspective +shops +maps +terminus +duncan +alien +fist +bridges +##pers +heroes +fed +derby +swallowed +##ros +patent +sara +illness +characterized +adventures +slide +hawaii +jurisdiction +##op +organised +##side +adelaide +walks +biology +se +##ties +rogers +swing +tightly +boundaries +##rie +prepare +implementation +stolen +##sha +certified +colombia +edwards +garage +##mm +recalled +##ball +rage +harm +nigeria +breast +##ren +furniture +pupils +settle +##lus +cuba +balls +client +alaska +21st +linear +thrust +celebration +latino +genetic +terror +##cia +##ening +lightning +fee +witness +lodge +establishing +skull +##ique +earning +hood +##ei +rebellion +wang +sporting +warned +missile +devoted +activist +porch +worship +fourteen +package +1871 +decorated +##shire +housed +##ock +chess +sailed +doctors +oscar +joan +treat +garcia +harbour +jeremy +##ire +traditions +dominant +jacques +##gon +##wan +relocated +1879 +amendment +sized +companion +simultaneously +volleyball +spun +acre +increases +stopping +loves +belongs +affect +drafted +tossed +scout +battles +1875 +filming +shoved +munich +tenure +vertical +romance +pc +##cher +argue +##ical +craft +ranging +www +opens +honest +tyler +yesterday +virtual +##let +muslims +reveal +snake +immigrants +radical +screaming +speakers +firing +saving +belonging +ease +lighting +prefecture +blame +farmer +hungry +grows +rubbed +beam +sur +subsidiary +##cha +armenian +sao +dropping +conventional +##fer +microsoft +reply +qualify +spots +1867 +sweat +festivals +##ken +immigration +physician +discover +exposure +sandy +explanation +isaac +implemented +##fish +hart +initiated +connect +stakes +presents +heights +householder +pleased +tourist +regardless +slip +closest +##ction +surely +sultan +brings +riley +preparation +aboard +slammed +baptist +experiment +ongoing +interstate +organic +playoffs +##ika +1877 +130 +##tar +hindu +error +tours +tier +plenty +arrangements +talks +trapped +excited +sank +ho +athens +1872 +denver +welfare +suburb +athletes +trick +diverse +belly +exclusively +yelled +1868 +##med +conversion +##ette +1874 +internationally +computers +conductor +abilities +sensitive +hello +dispute +measured +globe +rocket +prices +amsterdam +flights +tigers +inn +municipalities +emotion +references +3d +##mus +explains +airlines +manufactured +pm +archaeological +1873 +interpretation +devon +comment +##ites +settlements +kissing +absolute +improvement +suite +impressed +barcelona +sullivan +jefferson +towers +jesse +julie +##tin +##lu +grandson +hi +gauge +regard +rings +interviews +trace +raymond +thumb +departments +burns +serial +bulgarian +scores +demonstrated +##ix +1866 +kyle +alberta +underneath +romanized +##ward +relieved +acquisition +phrase +cliff +reveals +han +cuts +merger +custom +##dar +nee +gilbert +graduation +##nts +assessment +cafe +difficulty +demands +swung +democrat +jennifer +commons +1940s +grove +##yo +completing +focuses +sum +substitute +bearing +stretch +reception +##py +reflected +essentially +destination +pairs +##ched +survival +resource +##bach +promoting +doubles +messages +tear +##down +##fully +parade +florence +harvey +incumbent +partial +framework +900 +pedro +frozen +procedure +olivia +controls +##mic +shelter +personally +temperatures +##od +brisbane +tested +sits +marble +comprehensive +oxygen +leonard +##kov +inaugural +iranian +referring +quarters +attitude +##ivity +mainstream +lined +mars +dakota +norfolk +unsuccessful +##° +explosion +helicopter +congressional +##sing +inspector +bitch +seal +departed +divine +##ters +coaching +examination +punishment +manufacturer +sink +columns +unincorporated +signals +nevada +squeezed +dylan +dining +photos +martial +manuel +eighteen +elevator +brushed +plates +ministers +ivy +congregation +##len +slept +specialized +taxes +curve +restricted +negotiations +likes +statistical +arnold +inspiration +execution +bold +intermediate +significance +margin +ruler +wheels +gothic +intellectual +dependent +listened +eligible +buses +widow +syria +earn +cincinnati +collapsed +recipient +secrets +accessible +philippine +maritime +goddess +clerk +surrender +breaks +playoff +database +##ified +##lon +ideal +beetle +aspect +soap +regulation +strings +expand +anglo +shorter +crosses +retreat +tough +coins +wallace +directions +pressing +##oon +shipping +locomotives +comparison +topics +nephew +##mes +distinction +honors +travelled +sierra +ibn +##over +fortress +sa +recognised +carved +1869 +clients +##dan +intent +##mar +coaches +describing +bread +##ington +beaten +northwestern +##ona +merit +youtube +collapse +challenges +em +historians +objective +submitted +virus +attacking +drake +assume +##ere +diseases +marc +stem +leeds +##cus +##ab +farming +glasses +##lock +visits +nowhere +fellowship +relevant +carries +restaurants +experiments +101 +constantly +bases +targets +shah +tenth +opponents +verse +territorial +##ira +writings +corruption +##hs +instruction +inherited +reverse +emphasis +##vic +employee +arch +keeps +rabbi +watson +payment +uh +##ala +nancy +##tre +venice +fastest +sexy +banned +adrian +properly +ruth +touchdown +dollar +boards +metre +circles +edges +favour +comments +ok +travels +liberation +scattered +firmly +##ular +holland +permitted +diesel +kenya +den +originated +##ral +demons +resumed +dragged +rider +##rus +servant +blinked +extend +torn +##ias +##sey +input +meal +everybody +cylinder +kinds +camps +##fe +bullet +logic +##wn +croatian +evolved +healthy +fool +chocolate +wise +preserve +pradesh +##ess +respective +1850 +##ew +chicken +artificial +gross +corresponding +convicted +cage +caroline +dialogue +##dor +narrative +stranger +mario +br +christianity +failing +trent +commanding +buddhist +1848 +maurice +focusing +yale +bike +altitude +##ering +mouse +revised +##sley +veteran +##ig +pulls +theology +crashed +campaigns +legion +##ability +drag +excellence +customer +cancelled +intensity +excuse +##lar +liga +participating +contributing +printing +##burn +variable +##rk +curious +bin +legacy +renaissance +##my +symptoms +binding +vocalist +dancer +##nie +grammar +gospel +democrats +ya +enters +sc +diplomatic +hitler +##ser +clouds +mathematical +quit +defended +oriented +##heim +fundamental +hardware +impressive +equally +convince +confederate +guilt +chuck +sliding +##ware +magnetic +narrowed +petersburg +bulgaria +otto +phd +skill +##ama +reader +hopes +pitcher +reservoir +hearts +automatically +expecting +mysterious +bennett +extensively +imagined +seeds +monitor +fix +##ative +journalism +struggling +signature +ranch +encounter +photographer +observation +protests +##pin +influences +##hr +calendar +##all +cruz +croatia +locomotive +hughes +naturally +shakespeare +basement +hook +uncredited +faded +theories +approaches +dare +phillips +filling +fury +obama +##ain +efficient +arc +deliver +min +raid +breeding +inducted +leagues +efficiency +axis +montana +eagles +##ked +supplied +instructions +karen +picking +indicating +trap +anchor +practically +christians +tomb +vary +occasional +electronics +lords +readers +newcastle +faint +innovation +collect +situations +engagement +160 +claude +mixture +##feld +peer +tissue +logo +lean +##ration +°f +floors +##ven +architects +reducing +##our +##ments +rope +1859 +ottawa +##har +samples +banking +declaration +proteins +resignation +francois +saudi +advocate +exhibited +armor +twins +divorce +##ras +abraham +reviewed +jo +temporarily +matrix +physically +pulse +curled +##ena +difficulties +bengal +usage +##ban +annie +riders +certificate +##pi +holes +warsaw +distinctive +jessica +##mon +mutual +1857 +customs +circular +eugene +removal +loaded +mere +vulnerable +depicted +generations +dame +heir +enormous +lightly +climbing +pitched +lessons +pilots +nepal +ram +google +preparing +brad +louise +renowned +##₂ +liam +##ably +plaza +shaw +sophie +brilliant +bills +##bar +##nik +fucking +mainland +server +pleasant +seized +veterans +jerked +fail +beta +brush +radiation +stored +warmth +southeastern +nate +sin +raced +berkeley +joke +athlete +designation +trunk +##low +roland +qualification +archives +heels +artwork +receives +judicial +reserves +##bed +woke +installation +abu +floating +fake +lesser +excitement +interface +concentrated +addressed +characteristic +amanda +saxophone +monk +auto +##bus +releasing +egg +dies +interaction +defender +ce +outbreak +glory +loving +##bert +sequel +consciousness +http +awake +ski +enrolled +##ress +handling +rookie +brow +somebody +biography +warfare +amounts +contracts +presentation +fabric +dissolved +challenged +meter +psychological +lt +elevated +rally +accurate +##tha +hospitals +undergraduate +specialist +venezuela +exhibit +shed +nursing +protestant +fluid +structural +footage +jared +consistent +prey +##ska +succession +reflect +exile +lebanon +wiped +suspect +shanghai +resting +integration +preservation +marvel +variant +pirates +sheep +rounded +capita +sailing +colonies +manuscript +deemed +variations +clarke +functional +emerging +boxing +relaxed +curse +azerbaijan +heavyweight +nickname +editorial +rang +grid +tightened +earthquake +flashed +miguel +rushing +##ches +improvements +boxes +brooks +180 +consumption +molecular +felix +societies +repeatedly +variation +aids +civic +graphics +professionals +realm +autonomous +receiver +delayed +workshop +militia +chairs +trump +canyon +##point +harsh +extending +lovely +happiness +##jan +stake +eyebrows +embassy +wellington +hannah +##ella +sony +corners +bishops +swear +cloth +contents +xi +namely +commenced +1854 +stanford +nashville +courage +graphic +commitment +garrison +##bin +hamlet +clearing +rebels +attraction +literacy +cooking +ruins +temples +jenny +humanity +celebrate +hasn +freight +sixty +rebel +bastard +##art +newton +##ada +deer +##ges +##ching +smiles +delaware +singers +##ets +approaching +assists +flame +##ph +boulevard +barrel +planted +##ome +pursuit +##sia +consequences +posts +shallow +invitation +rode +depot +ernest +kane +rod +concepts +preston +topic +chambers +striking +blast +arrives +descendants +montgomery +ranges +worlds +##lay +##ari +span +chaos +praise +##ag +fewer +1855 +sanctuary +mud +fbi +##ions +programmes +maintaining +unity +harper +bore +handsome +closure +tournaments +thunder +nebraska +linda +facade +puts +satisfied +argentine +dale +cork +dome +panama +##yl +1858 +tasks +experts +##ates +feeding +equation +##las +##ida +##tu +engage +bryan +##ax +um +quartet +melody +disbanded +sheffield +blocked +gasped +delay +kisses +maggie +connects +##non +sts +poured +creator +publishers +##we +guided +ellis +extinct +hug +gaining +##ord +complicated +##bility +poll +clenched +investigate +##use +thereby +quantum +spine +cdp +humor +kills +administered +semifinals +##du +encountered +ignore +##bu +commentary +##maker +bother +roosevelt +140 +plains +halfway +flowing +cultures +crack +imprisoned +neighboring +airline +##ses +##view +##mate +##ec +gather +wolves +marathon +transformed +##ill +cruise +organisations +carol +punch +exhibitions +numbered +alarm +ratings +daddy +silently +##stein +queens +colours +impression +guidance +liu +tactical +##rat +marshal +della +arrow +##ings +rested +feared +tender +owns +bitter +advisor +escort +##ides +spare +farms +grants +##ene +dragons +encourage +colleagues +cameras +##und +sucked +pile +spirits +prague +statements +suspension +landmark +fence +torture +recreation +bags +permanently +survivors +pond +spy +predecessor +bombing +coup +##og +protecting +transformation +glow +##lands +##book +dug +priests +andrea +feat +barn +jumping +##chen +##ologist +##con +casualties +stern +auckland +pipe +serie +revealing +ba +##bel +trevor +mercy +spectrum +yang +consist +governing +collaborated +possessed +epic +comprises +blew +shane +##ack +lopez +honored +magical +sacrifice +judgment +perceived +hammer +mtv +baronet +tune +das +missionary +sheets +350 +neutral +oral +threatening +attractive +shade +aims +seminary +##master +estates +1856 +michel +wounds +refugees +manufacturers +##nic +mercury +syndrome +porter +##iya +##din +hamburg +identification +upstairs +purse +widened +pause +cared +breathed +affiliate +santiago +prevented +celtic +fisher +125 +recruited +byzantine +reconstruction +farther +##mp +diet +sake +au +spite +sensation +##ert +blank +separation +105 +##hon +vladimir +armies +anime +##lie +accommodate +orbit +cult +sofia +archive +##ify +##box +founders +sustained +disorder +honours +northeastern +mia +crops +violet +threats +blanket +fires +canton +followers +southwestern +prototype +voyage +assignment +altered +moderate +protocol +pistol +##eo +questioned +brass +lifting +1852 +math +authored +##ual +doug +dimensional +dynamic +##san +1851 +pronounced +grateful +quest +uncomfortable +boom +presidency +stevens +relating +politicians +chen +barrier +quinn +diana +mosque +tribal +cheese +palmer +portions +sometime +chester +treasure +wu +bend +download +millions +reforms +registration +##osa +consequently +monitoring +ate +preliminary +brandon +invented +ps +eaten +exterior +intervention +ports +documented +log +displays +lecture +sally +favourite +##itz +vermont +lo +invisible +isle +breed +##ator +journalists +relay +speaks +backward +explore +midfielder +actively +stefan +procedures +cannon +blond +kenneth +centered +servants +chains +libraries +malcolm +essex +henri +slavery +##hal +facts +fairy +coached +cassie +cats +washed +cop +##fi +announcement +item +2000s +vinyl +activated +marco +frontier +growled +curriculum +##das +loyal +accomplished +leslie +ritual +kenny +##00 +vii +napoleon +hollow +hybrid +jungle +stationed +friedrich +counted +##ulated +platinum +theatrical +seated +col +rubber +glen +1840 +diversity +healing +extends +id +provisions +administrator +columbus +##oe +tributary +te +assured +org +##uous +prestigious +examined +lectures +grammy +ronald +associations +bailey +allan +essays +flute +believing +consultant +proceedings +travelling +1853 +kit +kerala +yugoslavia +buddy +methodist +##ith +burial +centres +batman +##nda +discontinued +bo +dock +stockholm +lungs +severely +##nk +citing +manga +##ugh +steal +mumbai +iraqi +robot +celebrity +bride +broadcasts +abolished +pot +joel +overhead +franz +packed +reconnaissance +johann +acknowledged +introduce +handled +doctorate +developments +drinks +alley +palestine +##nis +##aki +proceeded +recover +bradley +grain +patch +afford +infection +nationalist +legendary +##ath +interchange +virtually +gen +gravity +exploration +amber +vital +wishes +powell +doctrine +elbow +screenplay +##bird +contribute +indonesian +pet +creates +##com +enzyme +kylie +discipline +drops +manila +hunger +##ien +layers +suffer +fever +bits +monica +keyboard +manages +##hood +searched +appeals +##bad +testament +grande +reid +##war +beliefs +congo +##ification +##dia +si +requiring +##via +casey +1849 +regret +streak +rape +depends +syrian +sprint +pound +tourists +upcoming +pub +##xi +tense +##els +practiced +echo +nationwide +guild +motorcycle +liz +##zar +chiefs +desired +elena +bye +precious +absorbed +relatives +booth +pianist +##mal +citizenship +exhausted +wilhelm +##ceae +##hed +noting +quarterback +urge +hectares +##gue +ace +holly +##tal +blonde +davies +parked +sustainable +stepping +twentieth +airfield +galaxy +nest +chip +##nell +tan +shaft +paulo +requirement +##zy +paradise +tobacco +trans +renewed +vietnamese +##cker +##ju +suggesting +catching +holmes +enjoying +md +trips +colt +holder +butterfly +nerve +reformed +cherry +bowling +trailer +carriage +goodbye +appreciate +toy +joshua +interactive +enabled +involve +##kan +collar +determination +bunch +facebook +recall +shorts +superintendent +episcopal +frustration +giovanni +nineteenth +laser +privately +array +circulation +##ovic +armstrong +deals +painful +permit +discrimination +##wi +aires +retiring +cottage +ni +##sta +horizon +ellen +jamaica +ripped +fernando +chapters +playstation +patron +lecturer +navigation +behaviour +genes +georgian +export +solomon +rivals +swift +seventeen +rodriguez +princeton +independently +sox +1847 +arguing +entity +casting +hank +criteria +oakland +geographic +milwaukee +reflection +expanding +conquest +dubbed +##tv +halt +brave +brunswick +doi +arched +curtis +divorced +predominantly +somerset +streams +ugly +zoo +horrible +curved +buenos +fierce +dictionary +vector +theological +unions +handful +stability +chan +punjab +segments +##lly +altar +ignoring +gesture +monsters +pastor +##stone +thighs +unexpected +operators +abruptly +coin +compiled +associates +improving +migration +pin +##ose +compact +collegiate +reserved +##urs +quarterfinals +roster +restore +assembled +hurry +oval +##cies +1846 +flags +martha +##del +victories +sharply +##rated +argues +deadly +neo +drawings +symbols +performer +##iel +griffin +restrictions +editing +andrews +java +journals +arabia +compositions +dee +pierce +removing +hindi +casino +runway +civilians +minds +nasa +hotels +##zation +refuge +rent +retain +potentially +conferences +suburban +conducting +##tto +##tions +##tle +descended +massacre +##cal +ammunition +terrain +fork +souls +counts +chelsea +durham +drives +cab +##bank +perth +realizing +palestinian +finn +simpson +##dal +betty +##ule +moreover +particles +cardinals +tent +evaluation +extraordinary +##oid +inscription +##works +wednesday +chloe +maintains +panels +ashley +trucks +##nation +cluster +sunlight +strikes +zhang +##wing +dialect +canon +##ap +tucked +##ws +collecting +##mas +##can +##sville +maker +quoted +evan +franco +aria +buying +cleaning +eva +closet +provision +apollo +clinic +rat +##ez +necessarily +ac +##gle +##ising +venues +flipped +cent +spreading +trustees +checking +authorized +##sco +disappointed +##ado +notion +duration +trumpet +hesitated +topped +brussels +rolls +theoretical +hint +define +aggressive +repeat +wash +peaceful +optical +width +allegedly +mcdonald +strict +copyright +##illa +investors +mar +jam +witnesses +sounding +miranda +michelle +privacy +hugo +harmony +##pp +valid +lynn +glared +nina +102 +headquartered +diving +boarding +gibson +##ncy +albanian +marsh +routine +dealt +enhanced +er +intelligent +substance +targeted +enlisted +discovers +spinning +observations +pissed +smoking +rebecca +capitol +visa +varied +costume +seemingly +indies +compensation +surgeon +thursday +arsenal +westminster +suburbs +rid +anglican +##ridge +knots +foods +alumni +lighter +fraser +whoever +portal +scandal +##ray +gavin +advised +instructor +flooding +terrorist +##ale +teenage +interim +senses +duck +teen +thesis +abby +eager +overcome +##ile +newport +glenn +rises +shame +##cc +prompted +priority +forgot +bomber +nicolas +protective +360 +cartoon +katherine +breeze +lonely +trusted +henderson +richardson +relax +banner +candy +palms +remarkable +##rio +legends +cricketer +essay +ordained +edmund +rifles +trigger +##uri +##away +sail +alert +1830 +audiences +penn +sussex +siblings +pursued +indianapolis +resist +rosa +consequence +succeed +avoided +1845 +##ulation +inland +##tie +##nna +counsel +profession +chronicle +hurried +##una +eyebrow +eventual +bleeding +innovative +cure +##dom +committees +accounting +con +scope +hardy +heather +tenor +gut +herald +codes +tore +scales +wagon +##oo +luxury +tin +prefer +fountain +triangle +bonds +darling +convoy +dried +traced +beings +troy +accidentally +slam +findings +smelled +joey +lawyers +outcome +steep +bosnia +configuration +shifting +toll +brook +performers +lobby +philosophical +construct +shrine +aggregate +boot +cox +phenomenon +savage +insane +solely +reynolds +lifestyle +##ima +nationally +holdings +consideration +enable +edgar +mo +mama +##tein +fights +relegation +chances +atomic +hub +conjunction +awkward +reactions +currency +finale +kumar +underwent +steering +elaborate +gifts +comprising +melissa +veins +reasonable +sunshine +chi +solve +trails +inhabited +elimination +ethics +huh +ana +molly +consent +apartments +layout +marines +##ces +hunters +bulk +##oma +hometown +##wall +##mont +cracked +reads +neighbouring +withdrawn +admission +wingspan +damned +anthology +lancashire +brands +batting +forgive +cuban +awful +##lyn +104 +dimensions +imagination +##ade +dante +##ship +tracking +desperately +goalkeeper +##yne +groaned +workshops +confident +burton +gerald +milton +circus +uncertain +slope +copenhagen +sophia +fog +philosopher +portraits +accent +cycling +varying +gripped +larvae +garrett +specified +scotia +mature +luther +kurt +rap +##kes +aerial +750 +ferdinand +heated +es +transported +##shan +safely +nonetheless +##orn +##gal +motors +demanding +##sburg +startled +##brook +ally +generate +caps +ghana +stained +demo +mentions +beds +ap +afterward +diary +##bling +utility +##iro +richards +1837 +conspiracy +conscious +shining +footsteps +observer +cyprus +urged +loyalty +developer +probability +olive +upgraded +gym +miracle +insects +graves +1844 +ourselves +hydrogen +amazon +katie +tickets +poets +##pm +planes +##pan +prevention +witnessed +dense +jin +randy +tang +warehouse +monroe +bang +archived +elderly +investigations +alec +granite +mineral +conflicts +controlling +aboriginal +carlo +##zu +mechanics +stan +stark +rhode +skirt +est +##berry +bombs +respected +##horn +imposed +limestone +deny +nominee +memphis +grabbing +disabled +##als +amusement +aa +frankfurt +corn +referendum +varies +slowed +disk +firms +unconscious +incredible +clue +sue +##zhou +twist +##cio +joins +idaho +chad +developers +computing +destroyer +103 +mortal +tucker +kingston +choices +yu +carson +1800 +os +whitney +geneva +pretend +dimension +staged +plateau +maya +##une +freestyle +##bc +rovers +hiv +##ids +tristan +classroom +prospect +##hus +honestly +diploma +lied +thermal +auxiliary +feast +unlikely +iata +##tel +morocco +pounding +treasury +lithuania +considerably +1841 +dish +1812 +geological +matching +stumbled +destroying +marched +brien +advances +cake +nicole +belle +settling +measuring +directing +##mie +tuesday +bassist +capabilities +stunned +fraud +torpedo +##list +##phone +anton +wisdom +surveillance +ruined +##ulate +lawsuit +healthcare +theorem +halls +trend +aka +horizontal +dozens +acquire +lasting +swim +hawk +gorgeous +fees +vicinity +decrease +adoption +tactics +##ography +pakistani +##ole +draws +##hall +willie +burke +heath +algorithm +integral +powder +elliott +brigadier +jackie +tate +varieties +darker +##cho +lately +cigarette +specimens +adds +##ree +##ensis +##inger +exploded +finalist +cia +murders +wilderness +arguments +nicknamed +acceptance +onwards +manufacture +robertson +jets +tampa +enterprises +blog +loudly +composers +nominations +1838 +ai +malta +inquiry +automobile +hosting +viii +rays +tilted +grief +museums +strategies +furious +euro +equality +cohen +poison +surrey +wireless +governed +ridiculous +moses +##esh +##room +vanished +##ito +barnes +attract +morrison +istanbul +##iness +absent +rotation +petition +janet +##logical +satisfaction +custody +deliberately +observatory +comedian +surfaces +pinyin +novelist +strictly +canterbury +oslo +monks +embrace +ibm +jealous +photograph +continent +dorothy +marina +doc +excess +holden +allegations +explaining +stack +avoiding +lance +storyline +majesty +poorly +spike +dos +bradford +raven +travis +classics +proven +voltage +pillow +fists +butt +1842 +interpreted +##car +1839 +gage +telegraph +lens +promising +expelled +casual +collector +zones +##min +silly +nintendo +##kh +##bra +downstairs +chef +suspicious +afl +flies +vacant +uganda +pregnancy +condemned +lutheran +estimates +cheap +decree +saxon +proximity +stripped +idiot +deposits +contrary +presenter +magnus +glacier +im +offense +edwin +##ori +upright +##long +bolt +##ois +toss +geographical +##izes +environments +delicate +marking +abstract +xavier +nails +windsor +plantation +occurring +equity +saskatchewan +fears +drifted +sequences +vegetation +revolt +##stic +1843 +sooner +fusion +opposing +nato +skating +1836 +secretly +ruin +lease +##oc +edit +##nne +flora +anxiety +ruby +##ological +##mia +tel +bout +taxi +emmy +frost +rainbow +compounds +foundations +rainfall +assassination +nightmare +dominican +##win +achievements +deserve +orlando +intact +armenia +##nte +calgary +valentine +106 +marion +proclaimed +theodore +bells +courtyard +thigh +gonzalez +console +troop +minimal +monte +everyday +##ence +##if +supporter +terrorism +buck +openly +presbyterian +activists +carpet +##iers +rubbing +uprising +##yi +cute +conceived +legally +##cht +millennium +cello +velocity +ji +rescued +cardiff +1835 +rex +concentrate +senators +beard +rendered +glowing +battalions +scouts +competitors +sculptor +catalogue +arctic +ion +raja +bicycle +wow +glancing +lawn +##woman +gentleman +lighthouse +publish +predicted +calculated +##val +variants +##gne +strain +##ui +winston +deceased +##nus +touchdowns +brady +caleb +sinking +echoed +crush +hon +blessed +protagonist +hayes +endangered +magnitude +editors +##tine +estimate +responsibilities +##mel +backup +laying +consumed +sealed +zurich +lovers +frustrated +##eau +ahmed +kicking +mit +treasurer +1832 +biblical +refuse +terrified +pump +agrees +genuine +imprisonment +refuses +plymouth +##hen +lou +##nen +tara +trembling +antarctic +ton +learns +##tas +crap +crucial +faction +atop +##borough +wrap +lancaster +odds +hopkins +erik +lyon +##eon +bros +##ode +snap +locality +tips +empress +crowned +cal +acclaimed +chuckled +##ory +clara +sends +mild +towel +##fl +##day +##а +wishing +assuming +interviewed +##bal +##die +interactions +eden +cups +helena +##lf +indie +beck +##fire +batteries +filipino +wizard +parted +##lam +traces +##born +rows +idol +albany +delegates +##ees +##sar +discussions +##ex +notre +instructed +belgrade +highways +suggestion +lauren +possess +orientation +alexandria +abdul +beats +salary +reunion +ludwig +alright +wagner +intimate +pockets +slovenia +hugged +brighton +merchants +cruel +stole +trek +slopes +repairs +enrollment +politically +underlying +promotional +counting +boeing +##bb +isabella +naming +##и +keen +bacteria +listing +separately +belfast +ussr +450 +lithuanian +anybody +ribs +sphere +martinez +cock +embarrassed +proposals +fragments +nationals +##fs +##wski +premises +fin +1500 +alpine +matched +freely +bounded +jace +sleeve +##af +gaming +pier +populated +evident +##like +frances +flooded +##dle +frightened +pour +trainer +framed +visitor +challenging +pig +wickets +##fold +infected +email +##pes +arose +##aw +reward +ecuador +oblast +vale +ch +shuttle +##usa +bach +rankings +forbidden +cornwall +accordance +salem +consumers +bruno +fantastic +toes +machinery +resolved +julius +remembering +propaganda +iceland +bombardment +tide +contacts +wives +##rah +concerto +macdonald +albania +implement +daisy +tapped +sudan +helmet +angela +mistress +##lic +crop +sunk +finest +##craft +hostile +##ute +##tsu +boxer +fr +paths +adjusted +habit +ballot +supervision +soprano +##zen +bullets +wicked +sunset +regiments +disappear +lamp +performs +app +##gia +##oa +rabbit +digging +incidents +entries +##cion +dishes +##oi +introducing +##ati +##fied +freshman +slot +jill +tackles +baroque +backs +##iest +lone +sponsor +destiny +altogether +convert +##aro +consensus +shapes +demonstration +basically +feminist +auction +artifacts +##bing +strongest +twitter +halifax +2019 +allmusic +mighty +smallest +precise +alexandra +viola +##los +##ille +manuscripts +##illo +dancers +ari +managers +monuments +blades +barracks +springfield +maiden +consolidated +electron +##end +berry +airing +wheat +nobel +inclusion +blair +payments +geography +bee +cc +eleanor +react +##hurst +afc +manitoba +##yu +su +lineup +fitness +recreational +investments +airborne +disappointment +##dis +edmonton +viewing +##row +renovation +##cast +infant +bankruptcy +roses +aftermath +pavilion +##yer +carpenter +withdrawal +ladder +##hy +discussing +popped +reliable +agreements +rochester +##abad +curves +bombers +220 +rao +reverend +decreased +choosing +107 +stiff +consulting +naples +crawford +tracy +ka +ribbon +cops +##lee +crushed +deciding +unified +teenager +accepting +flagship +explorer +poles +sanchez +inspection +revived +skilled +induced +exchanged +flee +locals +tragedy +swallow +loading +hanna +demonstrate +##ela +salvador +flown +contestants +civilization +##ines +wanna +rhodes +fletcher +hector +knocking +considers +##ough +nash +mechanisms +sensed +mentally +walt +unclear +##eus +renovated +madame +##cks +crews +governmental +##hin +undertaken +monkey +##ben +##ato +fatal +armored +copa +caves +governance +grasp +perception +certification +froze +damp +tugged +wyoming +##rg +##ero +newman +##lor +nerves +curiosity +graph +115 +##ami +withdraw +tunnels +dull +meredith +moss +exhibits +neighbors +communicate +accuracy +explored +raiders +republicans +secular +kat +superman +penny +criticised +##tch +freed +update +conviction +wade +ham +likewise +delegation +gotta +doll +promises +technological +myth +nationality +resolve +convent +##mark +sharon +dig +sip +coordinator +entrepreneur +fold +##dine +capability +councillor +synonym +blown +swan +cursed +1815 +jonas +haired +sofa +canvas +keeper +rivalry +##hart +rapper +speedway +swords +postal +maxwell +estonia +potter +recurring +##nn +##ave +errors +##oni +cognitive +1834 +##² +claws +nadu +roberto +bce +wrestler +ellie +##ations +infinite +ink +##tia +presumably +finite +staircase +108 +noel +patricia +nacional +##cation +chill +eternal +tu +preventing +prussia +fossil +limbs +##logist +ernst +frog +perez +rene +##ace +pizza +prussian +##ios +##vy +molecules +regulatory +answering +opinions +sworn +lengths +supposedly +hypothesis +upward +habitats +seating +ancestors +drank +yield +hd +synthesis +researcher +modest +##var +mothers +peered +voluntary +homeland +##the +acclaim +##igan +static +valve +luxembourg +alto +carroll +fe +receptor +norton +ambulance +##tian +johnston +catholics +depicting +jointly +elephant +gloria +mentor +badge +ahmad +distinguish +remarked +councils +precisely +allison +advancing +detection +crowded +##10 +cooperative +ankle +mercedes +dagger +surrendered +pollution +commit +subway +jeffrey +lesson +sculptures +provider +##fication +membrane +timothy +rectangular +fiscal +heating +teammate +basket +particle +anonymous +deployment +##ple +missiles +courthouse +proportion +shoe +sec +##ller +complaints +forbes +blacks +abandon +remind +sizes +overwhelming +autobiography +natalie +##awa +risks +contestant +countryside +babies +scorer +invaded +enclosed +proceed +hurling +disorders +##cu +reflecting +continuously +cruiser +graduates +freeway +investigated +ore +deserved +maid +blocking +phillip +jorge +shakes +dove +mann +variables +lacked +burden +accompanying +que +consistently +organizing +provisional +complained +endless +##rm +tubes +juice +georges +krishna +mick +labels +thriller +##uch +laps +arcade +sage +snail +##table +shannon +fi +laurence +seoul +vacation +presenting +hire +churchill +surprisingly +prohibited +savannah +technically +##oli +170 +##lessly +testimony +suited +speeds +toys +romans +mlb +flowering +measurement +talented +kay +settings +charleston +expectations +shattered +achieving +triumph +ceremonies +portsmouth +lanes +mandatory +loser +stretching +cologne +realizes +seventy +cornell +careers +webb +##ulating +americas +budapest +ava +suspicion +##ison +yo +conrad +##hai +sterling +jessie +rector +##az +1831 +transform +organize +loans +christine +volcanic +warrant +slender +summers +subfamily +newer +danced +dynamics +rhine +proceeds +heinrich +gastropod +commands +sings +facilitate +easter +ra +positioned +responses +expense +fruits +yanked +imported +25th +velvet +vic +primitive +tribune +baldwin +neighbourhood +donna +rip +hay +pr +##uro +1814 +espn +welcomed +##aria +qualifier +glare +highland +timing +##cted +shells +eased +geometry +louder +exciting +slovakia +##sion +##iz +##lot +savings +prairie +##ques +marching +rafael +tonnes +##lled +curtain +preceding +shy +heal +greene +worthy +##pot +detachment +bury +sherman +##eck +reinforced +seeks +bottles +contracted +duchess +outfit +walsh +##sc +mickey +##ase +geoffrey +archer +squeeze +dawson +eliminate +invention +##enberg +neal +##eth +stance +dealer +coral +maple +retire +polo +simplified +##ht +1833 +hid +watts +backwards +jules +##oke +genesis +mt +frames +rebounds +burma +woodland +moist +santos +whispers +drained +subspecies +##aa +streaming +ulster +burnt +correspondence +maternal +gerard +denis +stealing +##load +genius +duchy +##oria +inaugurated +momentum +suits +placement +sovereign +clause +thames +##hara +confederation +reservation +sketch +yankees +lets +rotten +charm +hal +verses +ultra +commercially +dot +salon +citation +adopt +winnipeg +mist +allocated +cairo +##boy +jenkins +interference +objectives +##wind +1820 +portfolio +armoured +sectors +##eh +initiatives +##world +integrity +exercises +robe +tap +ab +gazed +##tones +distracted +rulers +111 +favorable +jerome +tended +cart +factories +##eri +diplomat +valued +gravel +charitable +##try +calvin +exploring +chang +shepherd +terrace +pdf +pupil +##ural +reflects +ups +##rch +governors +shelf +depths +##nberg +trailed +crest +tackle +##nian +##ats +hatred +##kai +clare +makers +ethiopia +longtime +detected +embedded +lacking +slapped +rely +thomson +anticipation +iso +morton +successive +agnes +screenwriter +straightened +philippe +playwright +haunted +licence +iris +intentions +sutton +112 +logical +correctly +##weight +branded +licked +tipped +silva +ricky +narrator +requests +##ents +greeted +supernatural +cow +##wald +lung +refusing +employer +strait +gaelic +liner +##piece +zoe +sabha +##mba +driveway +harvest +prints +bates +reluctantly +threshold +algebra +ira +wherever +coupled +240 +assumption +picks +##air +designers +raids +gentlemen +##ean +roller +blowing +leipzig +locks +screw +dressing +strand +##lings +scar +dwarf +depicts +##nu +nods +##mine +differ +boris +##eur +yuan +flip +##gie +mob +invested +questioning +applying +##ture +shout +##sel +gameplay +blamed +illustrations +bothered +weakness +rehabilitation +##of +##zes +envelope +rumors +miners +leicester +subtle +kerry +##ico +ferguson +##fu +premiership +ne +##cat +bengali +prof +catches +remnants +dana +##rily +shouting +presidents +baltic +ought +ghosts +dances +sailors +shirley +fancy +dominic +##bie +madonna +##rick +bark +buttons +gymnasium +ashes +liver +toby +oath +providence +doyle +evangelical +nixon +cement +carnegie +embarked +hatch +surroundings +guarantee +needing +pirate +essence +##bee +filter +crane +hammond +projected +immune +percy +twelfth +##ult +regent +doctoral +damon +mikhail +##ichi +lu +critically +elect +realised +abortion +acute +screening +mythology +steadily +##fc +frown +nottingham +kirk +wa +minneapolis +##rra +module +algeria +mc +nautical +encounters +surprising +statues +availability +shirts +pie +alma +brows +munster +mack +soup +crater +tornado +sanskrit +cedar +explosive +bordered +dixon +planets +stamp +exam +happily +##bble +carriers +kidnapped +##vis +accommodation +emigrated +##met +knockout +correspondent +violation +profits +peaks +lang +specimen +agenda +ancestry +pottery +spelling +equations +obtaining +ki +linking +1825 +debris +asylum +##20 +buddhism +teddy +##ants +gazette +##nger +##sse +dental +eligibility +utc +fathers +averaged +zimbabwe +francesco +coloured +hissed +translator +lynch +mandate +humanities +mackenzie +uniforms +lin +##iana +##gio +asset +mhz +fitting +samantha +genera +wei +rim +beloved +shark +riot +entities +expressions +indo +carmen +slipping +owing +abbot +neighbor +sidney +##av +rats +recommendations +encouraging +squadrons +anticipated +commanders +conquered +##oto +donations +diagnosed +##mond +divide +##iva +guessed +decoration +vernon +auditorium +revelation +conversations +##kers +##power +herzegovina +dash +alike +protested +lateral +herman +accredited +mg +##gent +freeman +mel +fiji +crow +crimson +##rine +livestock +##pped +humanitarian +bored +oz +whip +##lene +##ali +legitimate +alter +grinning +spelled +anxious +oriental +wesley +##nin +##hole +carnival +controller +detect +##ssa +bowed +educator +kosovo +macedonia +##sin +occupy +mastering +stephanie +janeiro +para +unaware +nurses +noon +135 +cam +hopefully +ranger +combine +sociology +polar +rica +##eer +neill +##sman +holocaust +##ip +doubled +lust +1828 +109 +decent +cooling +unveiled +##card +1829 +nsw +homer +chapman +meyer +##gin +dive +mae +reagan +expertise +##gled +darwin +brooke +sided +prosecution +investigating +comprised +petroleum +genres +reluctant +differently +trilogy +johns +vegetables +corpse +highlighted +lounge +pension +unsuccessfully +elegant +aided +ivory +beatles +amelia +cain +dubai +sunny +immigrant +babe +click +##nder +underwater +pepper +combining +mumbled +atlas +horns +accessed +ballad +physicians +homeless +gestured +rpm +freak +louisville +corporations +patriots +prizes +rational +warn +modes +decorative +overnight +din +troubled +phantom +##ort +monarch +sheer +##dorf +generals +guidelines +organs +addresses +##zon +enhance +curling +parishes +cord +##kie +linux +caesar +deutsche +bavaria +##bia +coleman +cyclone +##eria +bacon +petty +##yama +##old +hampton +diagnosis +1824 +throws +complexity +rita +disputed +##₃ +pablo +##sch +marketed +trafficking +##ulus +examine +plague +formats +##oh +vault +faithful +##bourne +webster +##ox +highlights +##ient +##ann +phones +vacuum +sandwich +modeling +##gated +bolivia +clergy +qualities +isabel +##nas +##ars +wears +screams +reunited +annoyed +bra +##ancy +##rate +differential +transmitter +tattoo +container +poker +##och +excessive +resides +cowboys +##tum +augustus +trash +providers +statute +retreated +balcony +reversed +void +storey +preceded +masses +leap +laughs +neighborhoods +wards +schemes +falcon +santo +battlefield +pad +ronnie +thread +lesbian +venus +##dian +beg +sandstone +daylight +punched +gwen +analog +stroked +wwe +acceptable +measurements +dec +toxic +##kel +adequate +surgical +economist +parameters +varsity +##sberg +quantity +ella +##chy +##rton +countess +generating +precision +diamonds +expressway +ga +##ı +1821 +uruguay +talents +galleries +expenses +scanned +colleague +outlets +ryder +lucien +##ila +paramount +##bon +syracuse +dim +fangs +gown +sweep +##sie +toyota +missionaries +websites +##nsis +sentences +adviser +val +trademark +spells +##plane +patience +starter +slim +##borg +toe +incredibly +shoots +elliot +nobility +##wyn +cowboy +endorsed +gardner +tendency +persuaded +organisms +emissions +kazakhstan +amused +boring +chips +themed +##hand +llc +constantinople +chasing +systematic +guatemala +borrowed +erin +carey +##hard +highlands +struggles +1810 +##ifying +##ced +wong +exceptions +develops +enlarged +kindergarten +castro +##ern +##rina +leigh +zombie +juvenile +##most +consul +##nar +sailor +hyde +clarence +intensive +pinned +nasty +useless +jung +clayton +stuffed +exceptional +ix +apostolic +230 +transactions +##dge +exempt +swinging +cove +religions +##ash +shields +dairy +bypass +190 +pursuing +bug +joyce +bombay +chassis +southampton +chat +interact +redesignated +##pen +nascar +pray +salmon +rigid +regained +malaysian +grim +publicity +constituted +capturing +toilet +delegate +purely +tray +drift +loosely +striker +weakened +trinidad +mitch +itv +defines +transmitted +ming +scarlet +nodding +fitzgerald +fu +narrowly +sp +tooth +standings +virtue +##₁ +##wara +##cting +chateau +gloves +lid +##nel +hurting +conservatory +##pel +sinclair +reopened +sympathy +nigerian +strode +advocated +optional +chronic +discharge +##rc +suck +compatible +laurel +stella +shi +fails +wage +dodge +128 +informal +sorts +levi +buddha +villagers +##aka +chronicles +heavier +summoned +gateway +3000 +eleventh +jewelry +translations +accordingly +seas +##ency +fiber +pyramid +cubic +dragging +##ista +caring +##ops +android +contacted +lunar +##dt +kai +lisbon +patted +1826 +sacramento +theft +madagascar +subtropical +disputes +ta +holidays +piper +willow +mare +cane +itunes +newfoundland +benny +companions +dong +raj +observe +roar +charming +plaque +tibetan +fossils +enacted +manning +bubble +tina +tanzania +##eda +##hir +funk +swamp +deputies +cloak +ufc +scenario +par +scratch +metals +anthem +guru +engaging +specially +##boat +dialects +nineteen +cecil +duet +disability +messenger +unofficial +##lies +defunct +eds +moonlight +drainage +surname +puzzle +honda +switching +conservatives +mammals +knox +broadcaster +sidewalk +cope +##ried +benson +princes +peterson +##sal +bedford +sharks +eli +wreck +alberto +gasp +archaeology +lgbt +teaches +securities +madness +compromise +waving +coordination +davidson +visions +leased +possibilities +eighty +jun +fernandez +enthusiasm +assassin +sponsorship +reviewer +kingdoms +estonian +laboratories +##fy +##nal +applies +verb +celebrations +##zzo +rowing +lightweight +sadness +submit +mvp +balanced +dude +##vas +explicitly +metric +magnificent +mound +brett +mohammad +mistakes +irregular +##hing +##ass +sanders +betrayed +shipped +surge +##enburg +reporters +termed +georg +pity +verbal +bulls +abbreviated +enabling +appealed +##are +##atic +sicily +sting +heel +sweetheart +bart +spacecraft +brutal +monarchy +##tter +aberdeen +cameo +diane +##ub +survivor +clyde +##aries +complaint +##makers +clarinet +delicious +chilean +karnataka +coordinates +1818 +panties +##rst +pretending +ar +dramatically +kiev +bella +tends +distances +113 +catalog +launching +instances +telecommunications +portable +lindsay +vatican +##eim +angles +aliens +marker +stint +screens +bolton +##rne +judy +wool +benedict +plasma +europa +spark +imaging +filmmaker +swiftly +##een +contributor +##nor +opted +stamps +apologize +financing +butter +gideon +sophisticated +alignment +avery +chemicals +yearly +speculation +prominence +professionally +##ils +immortal +institutional +inception +wrists +identifying +tribunal +derives +gains +##wo +papal +preference +linguistic +vince +operative +brewery +##ont +unemployment +boyd +##ured +##outs +albeit +prophet +1813 +bi +##rr +##face +##rad +quarterly +asteroid +cleaned +radius +temper +##llen +telugu +jerk +viscount +menu +##ote +glimpse +##aya +yacht +hawaiian +baden +##rl +laptop +readily +##gu +monetary +offshore +scots +watches +##yang +##arian +upgrade +needle +xbox +lea +encyclopedia +flank +fingertips +##pus +delight +teachings +confirm +roth +beaches +midway +winters +##iah +teasing +daytime +beverly +gambling +bonnie +##backs +regulated +clement +hermann +tricks +knot +##shing +##uring +##vre +detached +ecological +owed +specialty +byron +inventor +bats +stays +screened +unesco +midland +trim +affection +##ander +##rry +jess +thoroughly +feedback +##uma +chennai +strained +heartbeat +wrapping +overtime +pleaded +##sworth +mon +leisure +oclc +##tate +##ele +feathers +angelo +thirds +nuts +surveys +clever +gill +commentator +##dos +darren +rides +gibraltar +##nc +##mu +dissolution +dedication +shin +meals +saddle +elvis +reds +chaired +taller +appreciation +functioning +niece +favored +advocacy +robbie +criminals +suffolk +yugoslav +passport +constable +congressman +hastings +vera +##rov +consecrated +sparks +ecclesiastical +confined +##ovich +muller +floyd +nora +1822 +paved +1827 +cumberland +ned +saga +spiral +##flow +appreciated +yi +collaborative +treating +similarities +feminine +finishes +##ib +jade +import +##nse +##hot +champagne +mice +securing +celebrities +helsinki +attributes +##gos +cousins +phases +ache +lucia +gandhi +submission +vicar +spear +shine +tasmania +biting +detention +constitute +tighter +seasonal +##gus +terrestrial +matthews +##oka +effectiveness +parody +philharmonic +##onic +1816 +strangers +encoded +consortium +guaranteed +regards +shifts +tortured +collision +supervisor +inform +broader +insight +theaters +armour +emeritus +blink +incorporates +mapping +##50 +##ein +handball +flexible +##nta +substantially +generous +thief +##own +carr +loses +1793 +prose +ucla +romeo +generic +metallic +realization +damages +mk +commissioners +zach +default +##ther +helicopters +lengthy +stems +spa +partnered +spectators +rogue +indication +penalties +teresa +1801 +sen +##tric +dalton +##wich +irving +photographic +##vey +dell +deaf +peters +excluded +unsure +##vable +patterson +crawled +##zio +resided +whipped +latvia +slower +ecole +pipes +employers +maharashtra +comparable +va +textile +pageant +##gel +alphabet +binary +irrigation +chartered +choked +antoine +offs +waking +supplement +##wen +quantities +demolition +regain +locate +urdu +folks +alt +114 +##mc +scary +andreas +whites +##ava +classrooms +mw +aesthetic +publishes +valleys +guides +cubs +johannes +bryant +conventions +affecting +##itt +drain +awesome +isolation +prosecutor +ambitious +apology +captive +downs +atmospheric +lorenzo +aisle +beef +foul +##onia +kidding +composite +disturbed +illusion +natives +##ffer +emi +rockets +riverside +wartime +painters +adolf +melted +##ail +uncertainty +simulation +hawks +progressed +meantime +builder +spray +breach +unhappy +regina +russians +##urg +determining +##tation +tram +1806 +##quin +aging +##12 +1823 +garion +rented +mister +diaz +terminated +clip +1817 +depend +nervously +disco +owe +defenders +shiva +notorious +disbelief +shiny +worcester +##gation +##yr +trailing +undertook +islander +belarus +limitations +watershed +fuller +overlooking +utilized +raphael +1819 +synthetic +breakdown +klein +##nate +moaned +memoir +lamb +practicing +##erly +cellular +arrows +exotic +##graphy +witches +117 +charted +rey +hut +hierarchy +subdivision +freshwater +giuseppe +aloud +reyes +qatar +marty +sideways +utterly +sexually +jude +prayers +mccarthy +softball +blend +damien +##gging +##metric +wholly +erupted +lebanese +negro +revenues +tasted +comparative +teamed +transaction +labeled +maori +sovereignty +parkway +trauma +gran +malay +121 +advancement +descendant +2020 +buzz +salvation +inventory +symbolic +##making +antarctica +mps +##gas +##bro +mohammed +myanmar +holt +submarines +tones +##lman +locker +patriarch +bangkok +emerson +remarks +predators +kin +afghan +confession +norwich +rental +emerge +advantages +##zel +rca +##hold +shortened +storms +aidan +##matic +autonomy +compliance +##quet +dudley +atp +##osis +1803 +motto +documentation +summary +professors +spectacular +christina +archdiocese +flashing +innocence +remake +##dell +psychic +reef +scare +employ +rs +sticks +meg +gus +leans +##ude +accompany +bergen +tomas +##iko +doom +wages +pools +##nch +##bes +breasts +scholarly +alison +outline +brittany +breakthrough +willis +realistic +##cut +##boro +competitor +##stan +pike +picnic +icon +designing +commercials +washing +villain +skiing +micro +costumes +auburn +halted +executives +##hat +logistics +cycles +vowel +applicable +barrett +exclaimed +eurovision +eternity +ramon +##umi +##lls +modifications +sweeping +disgust +##uck +torch +aviv +ensuring +rude +dusty +sonic +donovan +outskirts +cu +pathway +##band +##gun +##lines +disciplines +acids +cadet +paired +##40 +sketches +##sive +marriages +##⁺ +folding +peers +slovak +implies +admired +##beck +1880s +leopold +instinct +attained +weston +megan +horace +##ination +dorsal +ingredients +evolutionary +##its +complications +deity +lethal +brushing +levy +deserted +institutes +posthumously +delivering +telescope +coronation +motivated +rapids +luc +flicked +pays +volcano +tanner +weighed +##nica +crowds +frankie +gifted +addressing +granddaughter +winding +##rna +constantine +gomez +##front +landscapes +rudolf +anthropology +slate +werewolf +##lio +astronomy +circa +rouge +dreaming +sack +knelt +drowned +naomi +prolific +tracked +freezing +herb +##dium +agony +randall +twisting +wendy +deposit +touches +vein +wheeler +##bbled +##bor +batted +retaining +tire +presently +compare +specification +daemon +nigel +##grave +merry +recommendation +czechoslovakia +sandra +ng +roma +##sts +lambert +inheritance +sheikh +winchester +cries +examining +##yle +comeback +cuisine +nave +##iv +ko +retrieve +tomatoes +barker +polished +defining +irene +lantern +personalities +begging +tract +swore +1809 +175 +##gic +omaha +brotherhood +##rley +haiti +##ots +exeter +##ete +##zia +steele +dumb +pearson +210 +surveyed +elisabeth +trends +##ef +fritz +##rf +premium +bugs +fraction +calmly +viking +##birds +tug +inserted +unusually +##ield +confronted +distress +crashing +brent +turks +resign +##olo +cambodia +gabe +sauce +##kal +evelyn +116 +extant +clusters +quarry +teenagers +luna +##lers +##ister +affiliation +drill +##ashi +panthers +scenic +libya +anita +strengthen +inscriptions +##cated +lace +sued +judith +riots +##uted +mint +##eta +preparations +midst +dub +challenger +##vich +mock +cf +displaced +wicket +breaths +enables +schmidt +analyst +##lum +ag +highlight +automotive +axe +josef +newark +sufficiently +resembles +50th +##pal +flushed +mum +traits +##ante +commodore +incomplete +warming +titular +ceremonial +ethical +118 +celebrating +eighteenth +cao +lima +medalist +mobility +strips +snakes +##city +miniature +zagreb +barton +escapes +umbrella +automated +doubted +differs +cooled +georgetown +dresden +cooked +fade +wyatt +rna +jacobs +carlton +abundant +stereo +boost +madras +inning +##hia +spur +ip +malayalam +begged +osaka +groan +escaping +charging +dose +vista +##aj +bud +papa +communists +advocates +edged +tri +##cent +resemble +peaking +necklace +fried +montenegro +saxony +goose +glances +stuttgart +curator +recruit +grocery +sympathetic +##tting +##fort +127 +lotus +randolph +ancestor +##rand +succeeding +jupiter +1798 +macedonian +##heads +hiking +1808 +handing +fischer +##itive +garbage +node +##pies +prone +singular +papua +inclined +attractions +italia +pouring +motioned +grandma +garnered +jacksonville +corp +ego +ringing +aluminum +##hausen +ordering +##foot +drawer +traders +synagogue +##play +##kawa +resistant +wandering +fragile +fiona +teased +var +hardcore +soaked +jubilee +decisive +exposition +mercer +poster +valencia +hale +kuwait +1811 +##ises +##wr +##eed +tavern +gamma +122 +johan +##uer +airways +amino +gil +##ury +vocational +domains +torres +##sp +generator +folklore +outcomes +##keeper +canberra +shooter +fl +beams +confrontation +##lling +##gram +feb +aligned +forestry +pipeline +jax +motorway +conception +decay +##tos +coffin +##cott +stalin +1805 +escorted +minded +##nam +sitcom +purchasing +twilight +veronica +additions +passive +tensions +straw +123 +frequencies +1804 +refugee +cultivation +##iate +christie +clary +bulletin +crept +disposal +##rich +##zong +processor +crescent +##rol +bmw +emphasized +whale +nazis +aurora +##eng +dwelling +hauled +sponsors +toledo +mega +ideology +theatres +tessa +cerambycidae +saves +turtle +cone +suspects +kara +rusty +yelling +greeks +mozart +shades +cocked +participant +##tro +shire +spit +freeze +necessity +##cos +inmates +nielsen +councillors +loaned +uncommon +omar +peasants +botanical +offspring +daniels +formations +jokes +1794 +pioneers +sigma +licensing +##sus +wheelchair +polite +1807 +liquor +pratt +trustee +##uta +forewings +balloon +##zz +kilometre +camping +explicit +casually +shawn +foolish +teammates +nm +hassan +carrie +judged +satisfy +vanessa +knives +selective +cnn +flowed +##lice +eclipse +stressed +eliza +mathematician +cease +cultivated +##roy +commissions +browns +##ania +destroyers +sheridan +meadow +##rius +minerals +##cial +downstream +clash +gram +memoirs +ventures +baha +seymour +archie +midlands +edith +fare +flynn +invite +canceled +tiles +stabbed +boulder +incorporate +amended +camden +facial +mollusk +unreleased +descriptions +yoga +grabs +550 +raises +ramp +shiver +##rose +coined +pioneering +tunes +qing +warwick +tops +119 +melanie +giles +##rous +wandered +##inal +annexed +nov +30th +unnamed +##ished +organizational +airplane +normandy +stoke +whistle +blessing +violations +chased +holders +shotgun +##ctic +outlet +reactor +##vik +tires +tearing +shores +fortified +mascot +constituencies +nc +columnist +productive +tibet +##rta +lineage +hooked +oct +tapes +judging +cody +##gger +hansen +kashmir +triggered +##eva +solved +cliffs +##tree +resisted +anatomy +protesters +transparent +implied +##iga +injection +mattress +excluding +##mbo +defenses +helpless +devotion +##elli +growl +liberals +weber +phenomena +atoms +plug +##iff +mortality +apprentice +howe +convincing +aaa +swimmer +barber +leone +promptly +sodium +def +nowadays +arise +##oning +gloucester +corrected +dignity +norm +erie +##ders +elders +evacuated +sylvia +compression +##yar +hartford +pose +backpack +reasoning +accepts +24th +wipe +millimetres +marcel +##oda +dodgers +albion +1790 +overwhelmed +aerospace +oaks +1795 +showcase +acknowledge +recovering +nolan +ashe +hurts +geology +fashioned +disappearance +farewell +swollen +shrug +marquis +wimbledon +124 +rue +1792 +commemorate +reduces +experiencing +inevitable +calcutta +intel +##court +murderer +sticking +fisheries +imagery +bloom +280 +brake +##inus +gustav +hesitation +memorable +po +viral +beans +accidents +tunisia +antenna +spilled +consort +treatments +aye +perimeter +##gard +donation +hostage +migrated +banker +addiction +apex +lil +trout +##ously +conscience +##nova +rams +sands +genome +passionate +troubles +##lets +##set +amid +##ibility +##ret +higgins +exceed +vikings +##vie +payne +##zan +muscular +##ste +defendant +sucking +##wal +ibrahim +fuselage +claudia +vfl +europeans +snails +interval +##garh +preparatory +statewide +tasked +lacrosse +viktor +##lation +angola +##hra +flint +implications +employs +teens +patrons +stall +weekends +barriers +scrambled +nucleus +tehran +jenna +parsons +lifelong +robots +displacement +5000 +##bles +precipitation +##gt +knuckles +clutched +1802 +marrying +ecology +marx +accusations +declare +scars +kolkata +mat +meadows +bermuda +skeleton +finalists +vintage +crawl +coordinate +affects +subjected +orchestral +mistaken +##tc +mirrors +dipped +relied +260 +arches +candle +##nick +incorporating +wildly +fond +basilica +owl +fringe +rituals +whispering +stirred +feud +tertiary +slick +goat +honorable +whereby +skip +ricardo +stripes +parachute +adjoining +submerged +synthesizer +##gren +intend +positively +ninety +phi +beaver +partition +fellows +alexis +prohibition +carlisle +bizarre +fraternity +##bre +doubts +icy +cbc +aquatic +sneak +sonny +combines +airports +crude +supervised +spatial +merge +alfonso +##bic +corrupt +scan +undergo +##ams +disabilities +colombian +comparing +dolphins +perkins +##lish +reprinted +unanimous +bounced +hairs +underworld +midwest +semester +bucket +paperback +miniseries +coventry +demise +##leigh +demonstrations +sensor +rotating +yan +##hler +arrange +soils +##idge +hyderabad +labs +##dr +brakes +grandchildren +##nde +negotiated +rover +ferrari +continuation +directorate +augusta +stevenson +counterpart +gore +##rda +nursery +rican +ave +collectively +broadly +pastoral +repertoire +asserted +discovering +nordic +styled +fiba +cunningham +harley +middlesex +survives +tumor +tempo +zack +aiming +lok +urgent +##rade +##nto +devils +##ement +contractor +turin +##wl +##ool +bliss +repaired +simmons +moan +astronomical +cr +negotiate +lyric +1890s +lara +bred +clad +angus +pbs +##ience +engineered +posed +##lk +hernandez +possessions +elbows +psychiatric +strokes +confluence +electorate +lifts +campuses +lava +alps +##ep +##ution +##date +physicist +woody +##page +##ographic +##itis +juliet +reformation +sparhawk +320 +complement +suppressed +jewel +##½ +floated +##kas +continuity +sadly +##ische +inability +melting +scanning +paula +flour +judaism +safer +vague +##lm +solving +curb +##stown +financially +gable +bees +expired +miserable +cassidy +dominion +1789 +cupped +145 +robbery +facto +amos +warden +resume +tallest +marvin +ing +pounded +usd +declaring +gasoline +##aux +darkened +270 +650 +sophomore +##mere +erection +gossip +televised +risen +dial +##eu +pillars +##link +passages +profound +##tina +arabian +ashton +silicon +nail +##ead +##lated +##wer +##hardt +fleming +firearms +ducked +circuits +blows +waterloo +titans +##lina +atom +fireplace +cheshire +financed +activation +algorithms +##zzi +constituent +catcher +cherokee +partnerships +sexuality +platoon +tragic +vivian +guarded +whiskey +meditation +poetic +##late +##nga +##ake +porto +listeners +dominance +kendra +mona +chandler +factions +22nd +salisbury +attitudes +derivative +##ido +##haus +intake +paced +javier +illustrator +barrels +bias +cockpit +burnett +dreamed +ensuing +##anda +receptors +someday +hawkins +mattered +##lal +slavic +1799 +jesuit +cameroon +wasted +tai +wax +lowering +victorious +freaking +outright +hancock +librarian +sensing +bald +calcium +myers +tablet +announcing +barack +shipyard +pharmaceutical +##uan +greenwich +flush +medley +patches +wolfgang +pt +speeches +acquiring +exams +nikolai +##gg +hayden +kannada +##type +reilly +##pt +waitress +abdomen +devastated +capped +pseudonym +pharmacy +fulfill +paraguay +1796 +clicked +##trom +archipelago +syndicated +##hman +lumber +orgasm +rejection +clifford +lorraine +advent +mafia +rodney +brock +##ght +##used +##elia +cassette +chamberlain +despair +mongolia +sensors +developmental +upstream +##eg +##alis +spanning +165 +trombone +basque +seeded +interred +renewable +rhys +leapt +revision +molecule +##ages +chord +vicious +nord +shivered +23rd +arlington +debts +corpus +sunrise +bays +blackburn +centimetres +##uded +shuddered +gm +strangely +gripping +cartoons +isabelle +orbital +##ppa +seals +proving +##lton +refusal +strengthened +bust +assisting +baghdad +batsman +portrayal +mara +pushes +spears +og +##cock +reside +nathaniel +brennan +1776 +confirmation +caucus +##worthy +markings +yemen +nobles +ku +lazy +viewer +catalan +encompasses +sawyer +##fall +sparked +substances +patents +braves +arranger +evacuation +sergio +persuade +dover +tolerance +penguin +cum +jockey +insufficient +townships +occupying +declining +plural +processed +projection +puppet +flanders +introduces +liability +##yon +gymnastics +antwerp +taipei +hobart +candles +jeep +wes +observers +126 +chaplain +bundle +glorious +##hine +hazel +flung +sol +excavations +dumped +stares +sh +bangalore +triangular +icelandic +intervals +expressing +turbine +##vers +songwriting +crafts +##igo +jasmine +ditch +rite +##ways +entertaining +comply +sorrow +wrestlers +basel +emirates +marian +rivera +helpful +##some +caution +downward +networking +##atory +##tered +darted +genocide +emergence +replies +specializing +spokesman +convenient +unlocked +fading +augustine +concentrations +resemblance +elijah +investigator +andhra +##uda +promotes +bean +##rrell +fleeing +wan +simone +announcer +##ame +##bby +lydia +weaver +132 +residency +modification +##fest +stretches +##ast +alternatively +nat +lowe +lacks +##ented +pam +tile +concealed +inferior +abdullah +residences +tissues +vengeance +##ided +moisture +peculiar +groove +zip +bologna +jennings +ninja +oversaw +zombies +pumping +batch +livingston +emerald +installations +1797 +peel +nitrogen +rama +##fying +##star +schooling +strands +responding +werner +##ost +lime +casa +accurately +targeting +##rod +underway +##uru +hemisphere +lester +##yard +occupies +2d +griffith +angrily +reorganized +##owing +courtney +deposited +##dd +##30 +estadio +##ifies +dunn +exiled +##ying +checks +##combe +##о +##fly +successes +unexpectedly +blu +assessed +##flower +##ه +observing +sacked +spiders +kn +##tail +mu +nodes +prosperity +audrey +divisional +155 +broncos +tangled +adjust +feeds +erosion +paolo +surf +directory +snatched +humid +admiralty +screwed +gt +reddish +##nese +modules +trench +lamps +bind +leah +bucks +competes +##nz +##form +transcription +##uc +isles +violently +clutching +pga +cyclist +inflation +flats +ragged +unnecessary +##hian +stubborn +coordinated +harriet +baba +disqualified +330 +insect +wolfe +##fies +reinforcements +rocked +duel +winked +embraced +bricks +##raj +hiatus +defeats +pending +brightly +jealousy +##xton +##hm +##uki +lena +gdp +colorful +##dley +stein +kidney +##shu +underwear +wanderers +##haw +##icus +guardians +m³ +roared +habits +##wise +permits +gp +uranium +punished +disguise +bundesliga +elise +dundee +erotic +partisan +pi +collectors +float +individually +rendering +behavioral +bucharest +ser +hare +valerie +corporal +nutrition +proportional +##isa +immense +##kis +pavement +##zie +##eld +sutherland +crouched +1775 +##lp +suzuki +trades +endurance +operas +crosby +prayed +priory +rory +socially +##urn +gujarat +##pu +walton +cube +pasha +privilege +lennon +floods +thorne +waterfall +nipple +scouting +approve +##lov +minorities +voter +dwight +extensions +assure +ballroom +slap +dripping +privileges +rejoined +confessed +demonstrating +patriotic +yell +investor +##uth +pagan +slumped +squares +##cle +##kins +confront +bert +embarrassment +##aid +aston +urging +sweater +starr +yuri +brains +williamson +commuter +mortar +structured +selfish +exports +##jon +cds +##him +unfinished +##rre +mortgage +destinations +##nagar +canoe +solitary +buchanan +delays +magistrate +fk +##pling +motivation +##lier +##vier +recruiting +assess +##mouth +malik +antique +1791 +pius +rahman +reich +tub +zhou +smashed +airs +galway +xii +conditioning +honduras +discharged +dexter +##pf +lionel +129 +debates +lemon +tiffany +volunteered +dom +dioxide +procession +devi +sic +tremendous +advertisements +colts +transferring +verdict +hanover +decommissioned +utter +relate +pac +racism +##top +beacon +limp +similarity +terra +occurrence +ant +##how +becky +capt +updates +armament +richie +pal +##graph +halloween +mayo +##ssen +##bone +cara +serena +fcc +dolls +obligations +##dling +violated +lafayette +jakarta +exploitation +##ime +infamous +iconic +##lah +##park +kitty +moody +reginald +dread +spill +crystals +olivier +modeled +bluff +equilibrium +separating +notices +ordnance +extinction +onset +cosmic +attachment +sammy +expose +privy +anchored +##bil +abbott +admits +bending +baritone +emmanuel +policeman +vaughan +winged +climax +dresses +denny +polytechnic +mohamed +burmese +authentic +nikki +genetics +grandparents +homestead +gaza +postponed +metacritic +una +##sby +##bat +unstable +dissertation +##rial +##cian +curls +obscure +uncovered +bronx +praying +disappearing +##hoe +prehistoric +coke +turret +mutations +nonprofit +pits +monaco +##ي +##usion +prominently +dispatched +podium +##mir +uci +##uation +133 +fortifications +birthplace +kendall +##lby +##oll +preacher +rack +goodman +##rman +persistent +##ott +countless +jaime +recorder +lexington +persecution +jumps +renewal +wagons +##11 +crushing +##holder +decorations +##lake +abundance +wrath +laundry +£1 +garde +##rp +jeanne +beetles +peasant +##sl +splitting +caste +sergei +##rer +##ema +scripts +##ively +rub +satellites +##vor +inscribed +verlag +scrapped +gale +packages +chick +potato +slogan +kathleen +arabs +##culture +counterparts +reminiscent +choral +##tead +rand +retains +bushes +dane +accomplish +courtesy +closes +##oth +slaughter +hague +krakow +lawson +tailed +elias +ginger +##ttes +canopy +betrayal +rebuilding +turf +##hof +frowning +allegiance +brigades +kicks +rebuild +polls +alias +nationalism +td +rowan +audition +bowie +fortunately +recognizes +harp +dillon +horrified +##oro +renault +##tics +ropes +##α +presumed +rewarded +infrared +wiping +accelerated +illustration +##rid +presses +practitioners +badminton +##iard +detained +##tera +recognizing +relates +misery +##sies +##tly +reproduction +piercing +potatoes +thornton +esther +manners +hbo +##aan +ours +bullshit +ernie +perennial +sensitivity +illuminated +rupert +##jin +##iss +##ear +rfc +nassau +##dock +staggered +socialism +##haven +appointments +nonsense +prestige +sharma +haul +##tical +solidarity +gps +##ook +##rata +igor +pedestrian +##uit +baxter +tenants +wires +medication +unlimited +guiding +impacts +diabetes +##rama +sasha +pas +clive +extraction +131 +continually +constraints +##bilities +sonata +hunted +sixteenth +chu +planting +quote +mayer +pretended +abs +spat +##hua +ceramic +##cci +curtains +pigs +pitching +##dad +latvian +sore +dayton +##sted +##qi +patrols +slice +playground +##nted +shone +stool +apparatus +inadequate +mates +treason +##ija +desires +##liga +##croft +somalia +laurent +mir +leonardo +oracle +grape +obliged +chevrolet +thirteenth +stunning +enthusiastic +##ede +accounted +concludes +currents +basil +##kovic +drought +##rica +mai +##aire +shove +posting +##shed +pilgrimage +humorous +packing +fry +pencil +wines +smells +144 +marilyn +aching +newest +clung +bon +neighbours +sanctioned +##pie +mug +##stock +drowning +##mma +hydraulic +##vil +hiring +reminder +lilly +investigators +##ncies +sour +##eous +compulsory +packet +##rion +##graphic +##elle +cannes +##inate +depressed +##rit +heroic +importantly +theresa +##tled +conway +saturn +marginal +rae +##xia +corresponds +royce +pact +jasper +explosives +packaging +aluminium +##ttered +denotes +rhythmic +spans +assignments +hereditary +outlined +originating +sundays +lad +reissued +greeting +beatrice +##dic +pillar +marcos +plots +handbook +alcoholic +judiciary +avant +slides +extract +masculine +blur +##eum +##force +homage +trembled +owens +hymn +trey +omega +signaling +socks +accumulated +reacted +attic +theo +lining +angie +distraction +primera +talbot +##key +1200 +ti +creativity +billed +##hey +deacon +eduardo +identifies +proposition +dizzy +gunner +hogan +##yam +##pping +##hol +ja +##chan +jensen +reconstructed +##berger +clearance +darius +##nier +abe +harlem +plea +dei +circled +emotionally +notation +fascist +neville +exceeded +upwards +viable +ducks +##fo +workforce +racer +limiting +shri +##lson +possesses +1600 +kerr +moths +devastating +laden +disturbing +locking +##cture +gal +fearing +accreditation +flavor +aide +1870s +mountainous +##baum +melt +##ures +motel +texture +servers +soda +##mb +herd +##nium +erect +puzzled +hum +peggy +examinations +gould +testified +geoff +ren +devised +sacks +##law +denial +posters +grunted +cesar +tutor +ec +gerry +offerings +byrne +falcons +combinations +ct +incoming +pardon +rocking +26th +avengers +flared +mankind +seller +uttar +loch +nadia +stroking +exposing +##hd +fertile +ancestral +instituted +##has +noises +prophecy +taxation +eminent +vivid +pol +##bol +dart +indirect +multimedia +notebook +upside +displaying +adrenaline +referenced +geometric +##iving +progression +##ddy +blunt +announce +##far +implementing +##lav +aggression +liaison +cooler +cares +headache +plantations +gorge +dots +impulse +thickness +ashamed +averaging +kathy +obligation +precursor +137 +fowler +symmetry +thee +225 +hears +##rai +undergoing +ads +butcher +bowler +##lip +cigarettes +subscription +goodness +##ically +browne +##hos +##tech +kyoto +donor +##erty +damaging +friction +drifting +expeditions +hardened +prostitution +152 +fauna +blankets +claw +tossing +snarled +butterflies +recruits +investigative +coated +healed +138 +communal +hai +xiii +academics +boone +psychologist +restless +lahore +stephens +mba +brendan +foreigners +printer +##pc +ached +explode +27th +deed +scratched +dared +##pole +cardiac +1780 +okinawa +proto +commando +compelled +oddly +electrons +##base +replica +thanksgiving +##rist +sheila +deliberate +stafford +tidal +representations +hercules +ou +##path +##iated +kidnapping +lenses +##tling +deficit +samoa +mouths +consuming +computational +maze +granting +smirk +razor +fixture +ideals +inviting +aiden +nominal +##vs +issuing +julio +pitt +ramsey +docks +##oss +exhaust +##owed +bavarian +draped +anterior +mating +ethiopian +explores +noticing +##nton +discarded +convenience +hoffman +endowment +beasts +cartridge +mormon +paternal +probe +sleeves +interfere +lump +deadline +##rail +jenks +bulldogs +scrap +alternating +justified +reproductive +nam +seize +descending +secretariat +kirby +coupe +grouped +smash +panther +sedan +tapping +##18 +lola +cheer +germanic +unfortunate +##eter +unrelated +##fan +subordinate +##sdale +suzanne +advertisement +##ility +horsepower +##lda +cautiously +discourse +luigi +##mans +##fields +noun +prevalent +mao +schneider +everett +surround +governorate +kira +##avia +westward +##take +misty +rails +sustainability +134 +unused +##rating +packs +toast +unwilling +regulate +thy +suffrage +nile +awe +assam +definitions +travelers +affordable +##rb +conferred +sells +undefeated +beneficial +torso +basal +repeating +remixes +##pass +bahrain +cables +fang +##itated +excavated +numbering +statutory +##rey +deluxe +##lian +forested +ramirez +derbyshire +zeus +slamming +transfers +astronomer +banana +lottery +berg +histories +bamboo +##uchi +resurrection +posterior +bowls +vaguely +##thi +thou +preserving +tensed +offence +##inas +meyrick +callum +ridden +watt +langdon +tying +lowland +snorted +daring +truman +##hale +##girl +aura +overly +filing +weighing +goa +infections +philanthropist +saunders +eponymous +##owski +latitude +perspectives +reviewing +mets +commandant +radial +##kha +flashlight +reliability +koch +vowels +amazed +ada +elaine +supper +##rth +##encies +predator +debated +soviets +cola +##boards +##nah +compartment +crooked +arbitrary +fourteenth +##ctive +havana +majors +steelers +clips +profitable +ambush +exited +packers +##tile +nude +cracks +fungi +##е +limb +trousers +josie +shelby +tens +frederic +##ος +definite +smoothly +constellation +insult +baton +discs +lingering +##nco +conclusions +lent +staging +becker +grandpa +shaky +##tron +einstein +obstacles +sk +adverse +elle +economically +##moto +mccartney +thor +dismissal +motions +readings +nostrils +treatise +##pace +squeezing +evidently +prolonged +1783 +venezuelan +je +marguerite +beirut +takeover +shareholders +##vent +denise +digit +airplay +norse +##bbling +imaginary +pills +hubert +blaze +vacated +eliminating +##ello +vine +mansfield +##tty +retrospective +barrow +borne +clutch +bail +forensic +weaving +##nett +##witz +desktop +citadel +promotions +worrying +dorset +ieee +subdivided +##iating +manned +expeditionary +pickup +synod +chuckle +185 +barney +##rz +##ffin +functionality +karachi +litigation +meanings +uc +lick +turbo +anders +##ffed +execute +curl +oppose +ankles +typhoon +##د +##ache +##asia +linguistics +compassion +pressures +grazing +perfection +##iting +immunity +monopoly +muddy +backgrounds +136 +namibia +francesca +monitors +attracting +stunt +tuition +##ии +vegetable +##mates +##quent +mgm +jen +complexes +forts +##ond +cellar +bites +seventeenth +royals +flemish +failures +mast +charities +##cular +peruvian +capitals +macmillan +ipswich +outward +frigate +postgraduate +folds +employing +##ouse +concurrently +fiery +##tai +contingent +nightmares +monumental +nicaragua +##kowski +lizard +mal +fielding +gig +reject +##pad +harding +##ipe +coastline +##cin +##nos +beethoven +humphrey +innovations +##tam +##nge +norris +doris +solicitor +huang +obey +141 +##lc +niagara +##tton +shelves +aug +bourbon +curry +nightclub +specifications +hilton +##ndo +centennial +dispersed +worm +neglected +briggs +sm +font +kuala +uneasy +plc +##nstein +##bound +##aking +##burgh +awaiting +pronunciation +##bbed +##quest +eh +optimal +zhu +raped +greens +presided +brenda +worries +##life +venetian +marxist +turnout +##lius +refined +braced +sins +grasped +sunderland +nickel +speculated +lowell +cyrillic +communism +fundraising +resembling +colonists +mutant +freddie +usc +##mos +gratitude +##run +mural +##lous +chemist +wi +reminds +28th +steals +tess +pietro +##ingen +promoter +ri +microphone +honoured +rai +sant +##qui +feather +##nson +burlington +kurdish +terrorists +deborah +sickness +##wed +##eet +hazard +irritated +desperation +veil +clarity +##rik +jewels +xv +##gged +##ows +##cup +berkshire +unfair +mysteries +orchid +winced +exhaustion +renovations +stranded +obe +infinity +##nies +adapt +redevelopment +thanked +registry +olga +domingo +noir +tudor +ole +##atus +commenting +behaviors +##ais +crisp +pauline +probable +stirling +wigan +##bian +paralympics +panting +surpassed +##rew +luca +barred +pony +famed +##sters +cassandra +waiter +carolyn +exported +##orted +andres +destructive +deeds +jonah +castles +vacancy +suv +##glass +1788 +orchard +yep +famine +belarusian +sprang +##forth +skinny +##mis +administrators +rotterdam +zambia +zhao +boiler +discoveries +##ride +##physics +lucius +disappointing +outreach +spoon +##frame +qualifications +unanimously +enjoys +regency +##iidae +stade +realism +veterinary +rodgers +dump +alain +chestnut +castile +censorship +rumble +gibbs +##itor +communion +reggae +inactivated +logs +loads +##houses +homosexual +##iano +ale +informs +##cas +phrases +plaster +linebacker +ambrose +kaiser +fascinated +850 +limerick +recruitment +forge +mastered +##nding +leinster +rooted +threaten +##strom +borneo +##hes +suggestions +scholarships +propeller +documentaries +patronage +coats +constructing +invest +neurons +comet +entirety +shouts +identities +annoying +unchanged +wary +##antly +##ogy +neat +oversight +##kos +phillies +replay +constance +##kka +incarnation +humble +skies +minus +##acy +smithsonian +##chel +guerrilla +jar +cadets +##plate +surplus +audit +##aru +cracking +joanna +louisa +pacing +##lights +intentionally +##iri +diner +nwa +imprint +australians +tong +unprecedented +bunker +naive +specialists +ark +nichols +railing +leaked +pedal +##uka +shrub +longing +roofs +v8 +captains +neural +tuned +##ntal +##jet +emission +medina +frantic +codex +definitive +sid +abolition +intensified +stocks +enrique +sustain +genoa +oxide +##written +clues +cha +##gers +tributaries +fragment +venom +##rity +##ente +##sca +muffled +vain +sire +laos +##ingly +##hana +hastily +snapping +surfaced +sentiment +motive +##oft +contests +approximate +mesa +luckily +dinosaur +exchanges +propelled +accord +bourne +relieve +tow +masks +offended +##ues +cynthia +##mmer +rains +bartender +zinc +reviewers +lois +##sai +legged +arrogant +rafe +rosie +comprise +handicap +blockade +inlet +lagoon +copied +drilling +shelley +petals +##inian +mandarin +obsolete +##inated +onward +arguably +productivity +cindy +praising +seldom +busch +discusses +raleigh +shortage +ranged +stanton +encouragement +firstly +conceded +overs +temporal +##uke +cbe +##bos +woo +certainty +pumps +##pton +stalked +##uli +lizzie +periodic +thieves +weaker +##night +gases +shoving +chooses +wc +##chemical +prompting +weights +##kill +robust +flanked +sticky +hu +tuberculosis +##eb +##eal +christchurch +resembled +wallet +reese +inappropriate +pictured +distract +fixing +fiddle +giggled +burger +heirs +hairy +mechanic +torque +apache +obsessed +chiefly +cheng +logging +##tag +extracted +meaningful +numb +##vsky +gloucestershire +reminding +##bay +unite +##lit +breeds +diminished +clown +glove +1860s +##ن +##ug +archibald +focal +freelance +sliced +depiction +##yk +organism +switches +sights +stray +crawling +##ril +lever +leningrad +interpretations +loops +anytime +reel +alicia +delighted +##ech +inhaled +xiv +suitcase +bernie +vega +licenses +northampton +exclusion +induction +monasteries +racecourse +homosexuality +##right +##sfield +##rky +dimitri +michele +alternatives +ions +commentators +genuinely +objected +pork +hospitality +fencing +stephan +warships +peripheral +wit +drunken +wrinkled +quentin +spends +departing +chung +numerical +spokesperson +##zone +johannesburg +caliber +killers +##udge +assumes +neatly +demographic +abigail +bloc +##vel +mounting +##lain +bentley +slightest +xu +recipients +##jk +merlin +##writer +seniors +prisons +blinking +hindwings +flickered +kappa +##hel +80s +strengthening +appealing +brewing +gypsy +mali +lashes +hulk +unpleasant +harassment +bio +treaties +predict +instrumentation +pulp +troupe +boiling +mantle +##ffe +ins +##vn +dividing +handles +verbs +##onal +coconut +senegal +340 +thorough +gum +momentarily +##sto +cocaine +panicked +destined +##turing +teatro +denying +weary +captained +mans +##hawks +##code +wakefield +bollywood +thankfully +##16 +cyril +##wu +amendments +##bahn +consultation +stud +reflections +kindness +1787 +internally +##ovo +tex +mosaic +distribute +paddy +seeming +143 +##hic +piers +##15 +##mura +##verse +popularly +winger +kang +sentinel +mccoy +##anza +covenant +##bag +verge +fireworks +suppress +thrilled +dominate +##jar +swansea +##60 +142 +reconciliation +##ndi +stiffened +cue +dorian +##uf +damascus +amor +ida +foremost +##aga +porsche +unseen +dir +##had +##azi +stony +lexi +melodies +##nko +angular +integer +podcast +ants +inherent +jaws +justify +persona +##olved +josephine +##nr +##ressed +customary +flashes +gala +cyrus +glaring +backyard +ariel +physiology +greenland +html +stir +avon +atletico +finch +methodology +ked +##lent +mas +catholicism +townsend +branding +quincy +fits +containers +1777 +ashore +aragon +##19 +forearm +poisoning +##sd +adopting +conquer +grinding +amnesty +keller +finances +evaluate +forged +lankan +instincts +##uto +guam +bosnian +photographed +workplace +desirable +protector +##dog +allocation +intently +encourages +willy +##sten +bodyguard +electro +brighter +##ν +bihar +##chev +lasts +opener +amphibious +sal +verde +arte +##cope +captivity +vocabulary +yields +##tted +agreeing +desmond +pioneered +##chus +strap +campaigned +railroads +##ович +emblem +##dre +stormed +501 +##ulous +marijuana +northumberland +##gn +##nath +bowen +landmarks +beaumont +##qua +danube +##bler +attorneys +th +ge +flyers +critique +villains +cass +mutation +acc +##0s +colombo +mckay +motif +sampling +concluding +syndicate +##rell +neon +stables +ds +warnings +clint +mourning +wilkinson +##tated +merrill +leopard +evenings +exhaled +emil +sonia +ezra +discrete +stove +farrell +fifteenth +prescribed +superhero +##rier +worms +helm +wren +##duction +##hc +expo +##rator +hq +unfamiliar +antony +prevents +acceleration +fiercely +mari +painfully +calculations +cheaper +ign +clifton +irvine +davenport +mozambique +##np +pierced +##evich +wonders +##wig +##cate +##iling +crusade +ware +##uel +enzymes +reasonably +mls +##coe +mater +ambition +bunny +eliot +kernel +##fin +asphalt +headmaster +torah +aden +lush +pins +waived +##care +##yas +joao +substrate +enforce +##grad +##ules +alvarez +selections +epidemic +tempted +##bit +bremen +translates +ensured +waterfront +29th +forrest +manny +malone +kramer +reigning +cookies +simpler +absorption +205 +engraved +##ffy +evaluated +1778 +haze +146 +comforting +crossover +##abe +thorn +##rift +##imo +##pop +suppression +fatigue +cutter +##tr +201 +wurttemberg +##orf +enforced +hovering +proprietary +gb +samurai +syllable +ascent +lacey +tick +lars +tractor +merchandise +rep +bouncing +defendants +##yre +huntington +##ground +##oko +standardized +##hor +##hima +assassinated +nu +predecessors +rainy +liar +assurance +lyrical +##uga +secondly +flattened +ios +parameter +undercover +##mity +bordeaux +punish +ridges +markers +exodus +inactive +hesitate +debbie +nyc +pledge +savoy +nagar +offset +organist +##tium +hesse +marin +converting +##iver +diagram +propulsion +pu +validity +reverted +supportive +##dc +ministries +clans +responds +proclamation +##inae +##ø +##rea +ein +pleading +patriot +sf +birch +islanders +strauss +hates +##dh +brandenburg +concession +rd +##ob +1900s +killings +textbook +antiquity +cinematography +wharf +embarrassing +setup +creed +farmland +inequality +centred +signatures +fallon +370 +##ingham +##uts +ceylon +gazing +directive +laurie +##tern +globally +##uated +##dent +allah +excavation +threads +##cross +148 +frantically +icc +utilize +determines +respiratory +thoughtful +receptions +##dicate +merging +chandra +seine +147 +builders +builds +diagnostic +dev +visibility +goddamn +analyses +dhaka +cho +proves +chancel +concurrent +curiously +canadians +pumped +restoring +1850s +turtles +jaguar +sinister +spinal +traction +declan +vows +1784 +glowed +capitalism +swirling +install +universidad +##lder +##oat +soloist +##genic +##oor +coincidence +beginnings +nissan +dip +resorts +caucasus +combustion +infectious +##eno +pigeon +serpent +##itating +conclude +masked +salad +jew +##gr +surreal +toni +##wc +harmonica +151 +##gins +##etic +##coat +fishermen +intending +bravery +##wave +klaus +titan +wembley +taiwanese +ransom +40th +incorrect +hussein +eyelids +jp +cooke +dramas +utilities +##etta +##print +eisenhower +principally +granada +lana +##rak +openings +concord +##bl +bethany +connie +morality +sega +##mons +##nard +earnings +##kara +##cine +wii +communes +##rel +coma +composing +softened +severed +grapes +##17 +nguyen +analyzed +warlord +hubbard +heavenly +behave +slovenian +##hit +##ony +hailed +filmmakers +trance +caldwell +skye +unrest +coward +likelihood +##aging +bern +sci +taliban +honolulu +propose +##wang +1700 +browser +imagining +cobra +contributes +dukes +instinctively +conan +violinist +##ores +accessories +gradual +##amp +quotes +sioux +##dating +undertake +intercepted +sparkling +compressed +139 +fungus +tombs +haley +imposing +rests +degradation +lincolnshire +retailers +wetlands +tulsa +distributor +dungeon +nun +greenhouse +convey +atlantis +aft +exits +oman +dresser +lyons +##sti +joking +eddy +judgement +omitted +digits +##cts +##game +juniors +##rae +cents +stricken +une +##ngo +wizards +weir +breton +nan +technician +fibers +liking +royalty +##cca +154 +persia +terribly +magician +##rable +##unt +vance +cafeteria +booker +camille +warmer +##static +consume +cavern +gaps +compass +contemporaries +foyer +soothing +graveyard +maj +plunged +blush +##wear +cascade +demonstrates +ordinance +##nov +boyle +##lana +rockefeller +shaken +banjo +izzy +##ense +breathless +vines +##32 +##eman +alterations +chromosome +dwellings +feudal +mole +153 +catalonia +relics +tenant +mandated +##fm +fridge +hats +honesty +patented +raul +heap +cruisers +accusing +enlightenment +infants +wherein +chatham +contractors +zen +affinity +hc +osborne +piston +156 +traps +maturity +##rana +lagos +##zal +peering +##nay +attendant +dealers +protocols +subset +prospects +biographical +##cre +artery +##zers +insignia +nuns +endured +##eration +recommend +schwartz +serbs +berger +cromwell +crossroads +##ctor +enduring +clasped +grounded +##bine +marseille +twitched +abel +choke +https +catalyst +moldova +italians +##tist +disastrous +wee +##oured +##nti +wwf +nope +##piration +##asa +expresses +thumbs +167 +##nza +coca +1781 +cheating +##ption +skipped +sensory +heidelberg +spies +satan +dangers +semifinal +202 +bohemia +whitish +confusing +shipbuilding +relies +surgeons +landings +ravi +baku +moor +suffix +alejandro +##yana +litre +upheld +##unk +rajasthan +##rek +coaster +insists +posture +scenarios +etienne +favoured +appoint +transgender +elephants +poked +greenwood +defences +fulfilled +militant +somali +1758 +chalk +potent +##ucci +migrants +wink +assistants +nos +restriction +activism +niger +##ario +colon +shaun +##sat +daphne +##erated +swam +congregations +reprise +considerations +magnet +playable +xvi +##р +overthrow +tobias +knob +chavez +coding +##mers +propped +katrina +orient +newcomer +##suke +temperate +##pool +farmhouse +interrogation +##vd +committing +##vert +forthcoming +strawberry +joaquin +macau +ponds +shocking +siberia +##cellular +chant +contributors +##nant +##ologists +sped +absorb +hail +1782 +spared +##hore +barbados +karate +opus +originates +saul +##xie +evergreen +leaped +##rock +correlation +exaggerated +weekday +unification +bump +tracing +brig +afb +pathways +utilizing +##ners +mod +mb +disturbance +kneeling +##stad +##guchi +100th +pune +##thy +decreasing +168 +manipulation +miriam +academia +ecosystem +occupational +rbi +##lem +rift +##14 +rotary +stacked +incorporation +awakening +generators +guerrero +racist +##omy +cyber +derivatives +culminated +allie +annals +panzer +sainte +wikipedia +pops +zu +austro +##vate +algerian +politely +nicholson +mornings +educate +tastes +thrill +dartmouth +##gating +db +##jee +regan +differing +concentrating +choreography +divinity +##media +pledged +alexandre +routing +gregor +madeline +##idal +apocalypse +##hora +gunfire +culminating +elves +fined +liang +lam +programmed +tar +guessing +transparency +gabrielle +##gna +cancellation +flexibility +##lining +accession +shea +stronghold +nets +specializes +##rgan +abused +hasan +sgt +ling +exceeding +##₄ +admiration +supermarket +##ark +photographers +specialised +tilt +resonance +hmm +perfume +380 +sami +threatens +garland +botany +guarding +boiled +greet +puppy +russo +supplier +wilmington +vibrant +vijay +##bius +paralympic +grumbled +paige +faa +licking +margins +hurricanes +##gong +fest +grenade +ripping +##uz +counseling +weigh +##sian +needles +wiltshire +edison +costly +##not +fulton +tramway +redesigned +staffordshire +cache +gasping +watkins +sleepy +candidacy +##group +monkeys +timeline +throbbing +##bid +##sos +berth +uzbekistan +vanderbilt +bothering +overturned +ballots +gem +##iger +sunglasses +subscribers +hooker +compelling +ang +exceptionally +saloon +stab +##rdi +carla +terrifying +rom +##vision +coil +##oids +satisfying +vendors +31st +mackay +deities +overlooked +ambient +bahamas +felipe +olympia +whirled +botanist +advertised +tugging +##dden +disciples +morales +unionist +rites +foley +morse +motives +creepy +##₀ +soo +##sz +bargain +highness +frightening +turnpike +tory +reorganization +##cer +depict +biographer +##walk +unopposed +manifesto +##gles +institut +emile +accidental +kapoor +##dam +kilkenny +cortex +lively +##13 +romanesque +jain +shan +cannons +##ood +##ske +petrol +echoing +amalgamated +disappears +cautious +proposes +sanctions +trenton +##ر +flotilla +aus +contempt +tor +canary +cote +theirs +##hun +conceptual +deleted +fascinating +paso +blazing +elf +honourable +hutchinson +##eiro +##outh +##zin +surveyor +tee +amidst +wooded +reissue +intro +##ono +cobb +shelters +newsletter +hanson +brace +encoding +confiscated +dem +caravan +marino +scroll +melodic +cows +imam +##adi +##aneous +northward +searches +biodiversity +cora +310 +roaring +##bers +connell +theologian +halo +compose +pathetic +unmarried +dynamo +##oot +az +calculation +toulouse +deserves +humour +nr +forgiveness +tam +undergone +martyr +pamela +myths +whore +counselor +hicks +290 +heavens +battleship +electromagnetic +##bbs +stellar +establishments +presley +hopped +##chin +temptation +90s +wills +nas +##yuan +nhs +##nya +seminars +##yev +adaptations +gong +asher +lex +indicator +sikh +tobago +cites +goin +##yte +satirical +##gies +characterised +correspond +bubbles +lure +participates +##vid +eruption +skate +therapeutic +1785 +canals +wholesale +defaulted +sac +460 +petit +##zzled +virgil +leak +ravens +256 +portraying +##yx +ghetto +creators +dams +portray +vicente +##rington +fae +namesake +bounty +##arium +joachim +##ota +##iser +aforementioned +axle +snout +depended +dismantled +reuben +480 +##ibly +gallagher +##lau +##pd +earnest +##ieu +##iary +inflicted +objections +##llar +asa +gritted +##athy +jericho +##sea +##was +flick +underside +ceramics +undead +substituted +195 +eastward +undoubtedly +wheeled +chimney +##iche +guinness +cb +##ager +siding +##bell +traitor +baptiste +disguised +inauguration +149 +tipperary +choreographer +perched +warmed +stationary +eco +##ike +##ntes +bacterial +##aurus +flores +phosphate +##core +attacker +invaders +alvin +intersects +a1 +indirectly +immigrated +businessmen +cornelius +valves +narrated +pill +sober +ul +nationale +monastic +applicants +scenery +##jack +161 +motifs +constitutes +cpu +##osh +jurisdictions +sd +tuning +irritation +woven +##uddin +fertility +gao +##erie +antagonist +impatient +glacial +hides +boarded +denominations +interception +##jas +cookie +nicola +##tee +algebraic +marquess +bahn +parole +buyers +bait +turbines +paperwork +bestowed +natasha +renee +oceans +purchases +157 +vaccine +215 +##tock +fixtures +playhouse +integrate +jai +oswald +intellectuals +##cky +booked +nests +mortimer +##isi +obsession +sept +##gler +##sum +440 +scrutiny +simultaneous +squinted +##shin +collects +oven +shankar +penned +remarkably +##я +slips +luggage +spectral +1786 +collaborations +louie +consolidation +##ailed +##ivating +420 +hoover +blackpool +harness +ignition +vest +tails +belmont +mongol +skinner +##nae +visually +mage +derry +##tism +##unce +stevie +transitional +##rdy +redskins +drying +prep +prospective +##21 +annoyance +oversee +##loaded +fills +##books +##iki +announces +fda +scowled +respects +prasad +mystic +tucson +##vale +revue +springer +bankrupt +1772 +aristotle +salvatore +habsburg +##geny +dal +natal +nut +pod +chewing +darts +moroccan +walkover +rosario +lenin +punjabi +##ße +grossed +scattering +wired +invasive +hui +polynomial +corridors +wakes +gina +portrays +##cratic +arid +retreating +erich +irwin +sniper +##dha +linen +lindsey +maneuver +butch +shutting +socio +bounce +commemorative +postseason +jeremiah +pines +275 +mystical +beads +bp +abbas +furnace +bidding +consulted +assaulted +empirical +rubble +enclosure +sob +weakly +cancel +polly +yielded +##emann +curly +prediction +battered +70s +vhs +jacqueline +render +sails +barked +detailing +grayson +riga +sloane +raging +##yah +herbs +bravo +##athlon +alloy +giggle +imminent +suffers +assumptions +waltz +##itate +accomplishments +##ited +bathing +remixed +deception +prefix +##emia +deepest +##tier +##eis +balkan +frogs +##rong +slab +##pate +philosophers +peterborough +grains +imports +dickinson +rwanda +##atics +1774 +dirk +lan +tablets +##rove +clone +##rice +caretaker +hostilities +mclean +##gre +regimental +treasures +norms +impose +tsar +tango +diplomacy +variously +complain +192 +recognise +arrests +1779 +celestial +pulitzer +##dus +bing +libretto +##moor +adele +splash +##rite +expectation +lds +confronts +##izer +spontaneous +harmful +wedge +entrepreneurs +buyer +##ope +bilingual +translate +rugged +conner +circulated +uae +eaton +##gra +##zzle +lingered +lockheed +vishnu +reelection +alonso +##oom +joints +yankee +headline +cooperate +heinz +laureate +invading +##sford +echoes +scandinavian +##dham +hugging +vitamin +salute +micah +hind +trader +##sper +radioactive +##ndra +militants +poisoned +ratified +remark +campeonato +deprived +wander +prop +##dong +outlook +##tani +##rix +##eye +chiang +darcy +##oping +mandolin +spice +statesman +babylon +182 +walled +forgetting +afro +##cap +158 +giorgio +buffer +##polis +planetary +##gis +overlap +terminals +kinda +centenary +##bir +arising +manipulate +elm +ke +1770 +ak +##tad +chrysler +mapped +moose +pomeranian +quad +macarthur +assemblies +shoreline +recalls +stratford +##rted +noticeable +##evic +imp +##rita +##sque +accustomed +supplying +tents +disgusted +vogue +sipped +filters +khz +reno +selecting +luftwaffe +mcmahon +tyne +masterpiece +carriages +collided +dunes +exercised +flare +remembers +muzzle +##mobile +heck +##rson +burgess +lunged +middleton +boycott +bilateral +##sity +hazardous +lumpur +multiplayer +spotlight +jackets +goldman +liege +porcelain +rag +waterford +benz +attracts +hopeful +battling +ottomans +kensington +baked +hymns +cheyenne +lattice +levine +borrow +polymer +clashes +michaels +monitored +commitments +denounced +##25 +##von +cavity +##oney +hobby +akin +##holders +futures +intricate +cornish +patty +##oned +illegally +dolphin +##lag +barlow +yellowish +maddie +apologized +luton +plagued +##puram +nana +##rds +sway +fanny +łodz +##rino +psi +suspicions +hanged +##eding +initiate +charlton +##por +nak +competent +235 +analytical +annex +wardrobe +reservations +##rma +sect +162 +fairfax +hedge +piled +buckingham +uneven +bauer +simplicity +snyder +interpret +accountability +donors +moderately +byrd +continents +##cite +##max +disciple +hr +jamaican +ping +nominees +##uss +mongolian +diver +attackers +eagerly +ideological +pillows +miracles +apartheid +revolver +sulfur +clinics +moran +163 +##enko +ile +katy +rhetoric +##icated +chronology +recycling +##hrer +elongated +mughal +pascal +profiles +vibration +databases +domination +##fare +##rant +matthias +digest +rehearsal +polling +weiss +initiation +reeves +clinging +flourished +impress +ngo +##hoff +##ume +buckley +symposium +rhythms +weed +emphasize +transforming +##taking +##gence +##yman +accountant +analyze +flicker +foil +priesthood +voluntarily +decreases +##80 +##hya +slater +sv +charting +mcgill +##lde +moreno +##iu +besieged +zur +robes +##phic +admitting +api +deported +turmoil +peyton +earthquakes +##ares +nationalists +beau +clair +brethren +interrupt +welch +curated +galerie +requesting +164 +##ested +impending +steward +viper +##vina +complaining +beautifully +brandy +foam +nl +1660 +##cake +alessandro +punches +laced +explanations +##lim +attribute +clit +reggie +discomfort +##cards +smoothed +whales +##cene +adler +countered +duffy +disciplinary +widening +recipe +reliance +conducts +goats +gradient +preaching +##shaw +matilda +quasi +striped +meridian +cannabis +cordoba +certificates +##agh +##tering +graffiti +hangs +pilgrims +repeats +##ych +revive +urine +etat +##hawk +fueled +belts +fuzzy +susceptible +##hang +mauritius +salle +sincere +beers +hooks +##cki +arbitration +entrusted +advise +sniffed +seminar +junk +donnell +processors +principality +strapped +celia +mendoza +everton +fortunes +prejudice +starving +reassigned +steamer +##lund +tuck +evenly +foreman +##ffen +dans +375 +envisioned +slit +##xy +baseman +liberia +rosemary +##weed +electrified +periodically +potassium +stride +contexts +sperm +slade +mariners +influx +bianca +subcommittee +##rane +spilling +icao +estuary +##nock +delivers +iphone +##ulata +isa +mira +bohemian +dessert +##sbury +welcoming +proudly +slowing +##chs +musee +ascension +russ +##vian +waits +##psy +africans +exploit +##morphic +gov +eccentric +crab +peck +##ull +entrances +formidable +marketplace +groom +bolted +metabolism +patton +robbins +courier +payload +endure +##ifier +andes +refrigerator +##pr +ornate +##uca +ruthless +illegitimate +masonry +strasbourg +bikes +adobe +##³ +apples +quintet +willingly +niche +bakery +corpses +energetic +##cliffe +##sser +##ards +177 +centimeters +centro +fuscous +cretaceous +rancho +##yde +andrei +telecom +tottenham +oasis +ordination +vulnerability +presiding +corey +cp +penguins +sims +##pis +malawi +piss +##48 +correction +##cked +##ffle +##ryn +countdown +detectives +psychiatrist +psychedelic +dinosaurs +blouse +##get +choi +vowed +##oz +randomly +##pol +49ers +scrub +blanche +bruins +dusseldorf +##using +unwanted +##ums +212 +dominique +elevations +headlights +om +laguna +##oga +1750 +famously +ignorance +shrewsbury +##aine +ajax +breuning +che +confederacy +greco +overhaul +##screen +paz +skirts +disagreement +cruelty +jagged +phoebe +shifter +hovered +viruses +##wes +mandy +##lined +##gc +landlord +squirrel +dashed +##ι +ornamental +gag +wally +grange +literal +spurs +undisclosed +proceeding +yin +##text +billie +orphan +spanned +humidity +indy +weighted +presentations +explosions +lucian +##tary +vaughn +hindus +##anga +##hell +psycho +171 +daytona +protects +efficiently +rematch +sly +tandem +##oya +rebranded +impaired +hee +metropolis +peach +godfrey +diaspora +ethnicity +prosperous +gleaming +dar +grossing +playback +##rden +stripe +pistols +##tain +births +labelled +##cating +172 +rudy +alba +##onne +aquarium +hostility +##gb +##tase +shudder +sumatra +hardest +lakers +consonant +creeping +demos +homicide +capsule +zeke +liberties +expulsion +pueblo +##comb +trait +transporting +##ddin +##neck +##yna +depart +gregg +mold +ledge +hangar +oldham +playboy +termination +analysts +gmbh +romero +##itic +insist +cradle +filthy +brightness +slash +shootout +deposed +bordering +##truct +isis +microwave +tumbled +sheltered +cathy +werewolves +messy +andersen +convex +clapped +clinched +satire +wasting +edo +vc +rufus +##jak +mont +##etti +poznan +##keeping +restructuring +transverse +##rland +azerbaijani +slovene +gestures +roommate +choking +shear +##quist +vanguard +oblivious +##hiro +disagreed +baptism +##lich +coliseum +##aceae +salvage +societe +cory +locke +relocation +relying +versailles +ahl +swelling +##elo +cheerful +##word +##edes +gin +sarajevo +obstacle +diverted +##nac +messed +thoroughbred +fluttered +utrecht +chewed +acquaintance +assassins +dispatch +mirza +##wart +nike +salzburg +swell +yen +##gee +idle +ligue +samson +##nds +##igh +playful +spawned +##cise +tease +##case +burgundy +##bot +stirring +skeptical +interceptions +marathi +##dies +bedrooms +aroused +pinch +##lik +preferences +tattoos +buster +digitally +projecting +rust +##ital +kitten +priorities +addison +pseudo +##guard +dusk +icons +sermon +##psis +##iba +bt +##lift +##xt +ju +truce +rink +##dah +##wy +defects +psychiatry +offences +calculate +glucose +##iful +##rized +##unda +francaise +##hari +richest +warwickshire +carly +1763 +purity +redemption +lending +##cious +muse +bruises +cerebral +aero +carving +##name +preface +terminology +invade +monty +##int +anarchist +blurred +##iled +rossi +treats +guts +shu +foothills +ballads +undertaking +premise +cecilia +affiliates +blasted +conditional +wilder +minors +drone +rudolph +buffy +swallowing +horton +attested +##hop +rutherford +howell +primetime +livery +penal +##bis +minimize +hydro +wrecked +wrought +palazzo +##gling +cans +vernacular +friedman +nobleman +shale +walnut +danielle +##ection +##tley +sears +##kumar +chords +lend +flipping +streamed +por +dracula +gallons +sacrifices +gamble +orphanage +##iman +mckenzie +##gible +boxers +daly +##balls +##ان +208 +##ific +##rative +##iq +exploited +slated +##uity +circling +hillary +pinched +goldberg +provost +campaigning +lim +piles +ironically +jong +mohan +successors +usaf +##tem +##ught +autobiographical +haute +preserves +##ending +acquitted +comparisons +203 +hydroelectric +gangs +cypriot +torpedoes +rushes +chrome +derive +bumps +instability +fiat +pets +##mbe +silas +dye +reckless +settler +##itation +info +heats +##writing +176 +canonical +maltese +fins +mushroom +stacy +aspen +avid +##kur +##loading +vickers +gaston +hillside +statutes +wilde +gail +kung +sabine +comfortably +motorcycles +##rgo +169 +pneumonia +fetch +##sonic +axel +faintly +parallels +##oop +mclaren +spouse +compton +interdisciplinary +miner +##eni +181 +clamped +##chal +##llah +separates +versa +##mler +scarborough +labrador +##lity +##osing +rutgers +hurdles +como +166 +burt +divers +##100 +wichita +cade +coincided +##erson +bruised +mla +##pper +vineyard +##ili +##brush +notch +mentioning +jase +hearted +kits +doe +##acle +pomerania +##ady +ronan +seizure +pavel +problematic +##zaki +domenico +##ulin +catering +penelope +dependence +parental +emilio +ministerial +atkinson +##bolic +clarkson +chargers +colby +grill +peeked +arises +summon +##aged +fools +##grapher +faculties +qaeda +##vial +garner +refurbished +##hwa +geelong +disasters +nudged +bs +shareholder +lori +algae +reinstated +rot +##ades +##nous +invites +stainless +183 +inclusive +##itude +diocesan +til +##icz +denomination +##xa +benton +floral +registers +##ider +##erman +##kell +absurd +brunei +guangzhou +hitter +retaliation +##uled +##eve +blanc +nh +consistency +contamination +##eres +##rner +dire +palermo +broadcasters +diaries +inspire +vols +brewer +tightening +ky +mixtape +hormone +##tok +stokes +##color +##dly +##ssi +pg +##ometer +##lington +sanitation +##tility +intercontinental +apps +##adt +¹⁄₂ +cylinders +economies +favourable +unison +croix +gertrude +odyssey +vanity +dangling +##logists +upgrades +dice +middleweight +practitioner +##ight +206 +henrik +parlor +orion +angered +lac +python +blurted +##rri +sensual +intends +swings +angled +##phs +husky +attain +peerage +precinct +textiles +cheltenham +shuffled +dai +confess +tasting +bhutan +##riation +tyrone +segregation +abrupt +ruiz +##rish +smirked +blackwell +confidential +browning +amounted +##put +vase +scarce +fabulous +raided +staple +guyana +unemployed +glider +shay +##tow +carmine +troll +intervene +squash +superstar +##uce +cylindrical +len +roadway +researched +handy +##rium +##jana +meta +lao +declares +##rring +##tadt +##elin +##kova +willem +shrubs +napoleonic +realms +skater +qi +volkswagen +##ł +tad +hara +archaeologist +awkwardly +eerie +##kind +wiley +##heimer +##24 +titus +organizers +cfl +crusaders +lama +usb +vent +enraged +thankful +occupants +maximilian +##gaard +possessing +textbooks +##oran +collaborator +quaker +##ulo +avalanche +mono +silky +straits +isaiah +mustang +surged +resolutions +potomac +descend +cl +kilograms +plato +strains +saturdays +##olin +bernstein +##ype +holstein +ponytail +##watch +belize +conversely +heroine +perpetual +##ylus +charcoal +piedmont +glee +negotiating +backdrop +prologue +##jah +##mmy +pasadena +climbs +ramos +sunni +##holm +##tner +##tri +anand +deficiency +hertfordshire +stout +##avi +aperture +orioles +##irs +doncaster +intrigued +bombed +coating +otis +##mat +cocktail +##jit +##eto +amir +arousal +sar +##proof +##act +##ories +dixie +pots +##bow +whereabouts +159 +##fted +drains +bullying +cottages +scripture +coherent +fore +poe +appetite +##uration +sampled +##ators +##dp +derrick +rotor +jays +peacock +installment +##rro +advisors +##coming +rodeo +scotch +##mot +##db +##fen +##vant +ensued +rodrigo +dictatorship +martyrs +twenties +##н +towed +incidence +marta +rainforest +sai +scaled +##cles +oceanic +qualifiers +symphonic +mcbride +dislike +generalized +aubrey +colonization +##iation +##lion +##ssing +disliked +lublin +salesman +##ulates +spherical +whatsoever +sweating +avalon +contention +punt +severity +alderman +atari +##dina +##grant +##rop +scarf +seville +vertices +annexation +fairfield +fascination +inspiring +launches +palatinate +regretted +##rca +feral +##iom +elk +nap +olsen +reddy +yong +##leader +##iae +garment +transports +feng +gracie +outrage +viceroy +insides +##esis +breakup +grady +organizer +softer +grimaced +222 +murals +galicia +arranging +vectors +##rsten +bas +##sb +##cens +sloan +##eka +bitten +ara +fender +nausea +bumped +kris +banquet +comrades +detector +persisted +##llan +adjustment +endowed +cinemas +##shot +sellers +##uman +peek +epa +kindly +neglect +simpsons +talon +mausoleum +runaway +hangul +lookout +##cic +rewards +coughed +acquainted +chloride +##ald +quicker +accordion +neolithic +##qa +artemis +coefficient +lenny +pandora +tx +##xed +ecstasy +litter +segunda +chairperson +gemma +hiss +rumor +vow +nasal +antioch +compensate +patiently +transformers +##eded +judo +morrow +penis +posthumous +philips +bandits +husbands +denote +flaming +##any +##phones +langley +yorker +1760 +walters +##uo +##kle +gubernatorial +fatty +samsung +leroy +outlaw +##nine +unpublished +poole +jakob +##ᵢ +##ₙ +crete +distorted +superiority +##dhi +intercept +crust +mig +claus +crashes +positioning +188 +stallion +301 +frontal +armistice +##estinal +elton +aj +encompassing +camel +commemorated +malaria +woodward +calf +cigar +penetrate +##oso +willard +##rno +##uche +illustrate +amusing +convergence +noteworthy +##lma +##rva +journeys +realise +manfred +##sable +410 +##vocation +hearings +fiance +##posed +educators +provoked +adjusting +##cturing +modular +stockton +paterson +vlad +rejects +electors +selena +maureen +##tres +uber +##rce +swirled +##num +proportions +nanny +pawn +naturalist +parma +apostles +awoke +ethel +wen +##bey +monsoon +overview +##inating +mccain +rendition +risky +adorned +##ih +equestrian +germain +nj +conspicuous +confirming +##yoshi +shivering +##imeter +milestone +rumours +flinched +bounds +smacked +token +##bei +lectured +automobiles +##shore +impacted +##iable +nouns +nero +##leaf +ismail +prostitute +trams +##lace +bridget +sud +stimulus +impressions +reins +revolves +##oud +##gned +giro +honeymoon +##swell +criterion +##sms +##uil +libyan +prefers +##osition +211 +preview +sucks +accusation +bursts +metaphor +diffusion +tolerate +faye +betting +cinematographer +liturgical +specials +bitterly +humboldt +##ckle +flux +rattled +##itzer +archaeologists +odor +authorised +marshes +discretion +##ов +alarmed +archaic +inverse +##leton +explorers +##pine +drummond +tsunami +woodlands +##minate +##tland +booklet +insanity +owning +insert +crafted +calculus +##tore +receivers +##bt +stung +##eca +##nched +prevailing +travellers +eyeing +lila +graphs +##borne +178 +julien +##won +morale +adaptive +therapist +erica +cw +libertarian +bowman +pitches +vita +##ional +crook +##ads +##entation +caledonia +mutiny +##sible +1840s +automation +##ß +flock +##pia +ironic +pathology +##imus +remarried +##22 +joker +withstand +energies +##att +shropshire +hostages +madeleine +tentatively +conflicting +mateo +recipes +euros +ol +mercenaries +nico +##ndon +albuquerque +augmented +mythical +bel +freud +##child +cough +##lica +365 +freddy +lillian +genetically +nuremberg +calder +209 +bonn +outdoors +paste +suns +urgency +vin +restraint +tyson +##cera +##selle +barrage +bethlehem +kahn +##par +mounts +nippon +barony +happier +ryu +makeshift +sheldon +blushed +castillo +barking +listener +taped +bethel +fluent +headlines +pornography +rum +disclosure +sighing +mace +doubling +gunther +manly +##plex +rt +interventions +physiological +forwards +emerges +##tooth +##gny +compliment +rib +recession +visibly +barge +faults +connector +exquisite +prefect +##rlin +patio +##cured +elevators +brandt +italics +pena +173 +wasp +satin +ea +botswana +graceful +respectable +##jima +##rter +##oic +franciscan +generates +##dl +alfredo +disgusting +##olate +##iously +sherwood +warns +cod +promo +cheryl +sino +##ة +##escu +twitch +##zhi +brownish +thom +ortiz +##dron +densely +##beat +carmel +reinforce +##bana +187 +anastasia +downhill +vertex +contaminated +remembrance +harmonic +homework +##sol +fiancee +gears +olds +angelica +loft +ramsay +quiz +colliery +sevens +##cape +autism +##hil +walkway +##boats +ruben +abnormal +ounce +khmer +##bbe +zachary +bedside +morphology +punching +##olar +sparrow +convinces +##35 +hewitt +queer +remastered +rods +mabel +solemn +notified +lyricist +symmetric +##xide +174 +encore +passports +wildcats +##uni +baja +##pac +mildly +##ease +bleed +commodity +mounds +glossy +orchestras +##omo +damian +prelude +ambitions +##vet +awhile +remotely +##aud +asserts +imply +##iques +distinctly +modelling +remedy +##dded +windshield +dani +xiao +##endra +audible +powerplant +1300 +invalid +elemental +acquisitions +##hala +immaculate +libby +plata +smuggling +ventilation +denoted +minh +##morphism +430 +differed +dion +kelley +lore +mocking +sabbath +spikes +hygiene +drown +runoff +stylized +tally +liberated +aux +interpreter +righteous +aba +siren +reaper +pearce +millie +##cier +##yra +gaius +##iso +captures +##ttering +dorm +claudio +##sic +benches +knighted +blackness +##ored +discount +fumble +oxidation +routed +##ς +novak +perpendicular +spoiled +fracture +splits +##urt +pads +topology +##cats +axes +fortunate +offenders +protestants +esteem +221 +broadband +convened +frankly +hound +prototypes +isil +facilitated +keel +##sher +sahara +awaited +bubba +orb +prosecutors +186 +hem +520 +##xing +relaxing +remnant +romney +sorted +slalom +stefano +ulrich +##active +exemption +folder +pauses +foliage +hitchcock +epithet +204 +criticisms +##aca +ballistic +brody +hinduism +chaotic +youths +equals +##pala +pts +thicker +analogous +capitalist +improvised +overseeing +sinatra +ascended +beverage +##tl +straightforward +##kon +curran +##west +bois +325 +induce +surveying +emperors +sax +unpopular +##kk +cartoonist +fused +##mble +unto +##yuki +localities +##cko +##ln +darlington +slain +academie +lobbying +sediment +puzzles +##grass +defiance +dickens +manifest +tongues +alumnus +arbor +coincide +184 +appalachian +mustafa +examiner +cabaret +traumatic +yves +bracelet +draining +heroin +magnum +baths +odessa +consonants +mitsubishi +##gua +kellan +vaudeville +##fr +joked +null +straps +probation +##ław +ceded +interfaces +##pas +##zawa +blinding +viet +224 +rothschild +museo +640 +huddersfield +##vr +tactic +##storm +brackets +dazed +incorrectly +##vu +reg +glazed +fearful +manifold +benefited +irony +##sun +stumbling +##rte +willingness +balkans +mei +wraps +##aba +injected +##lea +gu +syed +harmless +##hammer +bray +takeoff +poppy +timor +cardboard +astronaut +purdue +weeping +southbound +cursing +stalls +diagonal +##neer +lamar +bryce +comte +weekdays +harrington +##uba +negatively +##see +lays +grouping +##cken +##henko +affirmed +halle +modernist +##lai +hodges +smelling +aristocratic +baptized +dismiss +justification +oilers +##now +coupling +qin +snack +healer +##qing +gardener +layla +battled +formulated +stephenson +gravitational +##gill +##jun +1768 +granny +coordinating +suites +##cd +##ioned +monarchs +##cote +##hips +sep +blended +apr +barrister +deposition +fia +mina +policemen +paranoid +##pressed +churchyard +covert +crumpled +creep +abandoning +tr +transmit +conceal +barr +understands +readiness +spire +##cology +##enia +##erry +610 +startling +unlock +vida +bowled +slots +##nat +##islav +spaced +trusting +admire +rig +##ink +slack +##70 +mv +207 +casualty +##wei +classmates +##odes +##rar +##rked +amherst +furnished +evolve +foundry +menace +mead +##lein +flu +wesleyan +##kled +monterey +webber +##vos +wil +##mith +##на +bartholomew +justices +restrained +##cke +amenities +191 +mediated +sewage +trenches +ml +mainz +##thus +1800s +##cula +##inski +caine +bonding +213 +converts +spheres +superseded +marianne +crypt +sweaty +ensign +historia +##br +spruce +##post +##ask +forks +thoughtfully +yukon +pamphlet +ames +##uter +karma +##yya +bryn +negotiation +sighs +incapable +##mbre +##ntial +actresses +taft +##mill +luce +prevailed +##amine +1773 +motionless +envoy +testify +investing +sculpted +instructors +provence +kali +cullen +horseback +##while +goodwin +##jos +gaa +norte +##ldon +modify +wavelength +abd +214 +skinned +sprinter +forecast +scheduling +marries +squared +tentative +##chman +boer +##isch +bolts +swap +fisherman +assyrian +impatiently +guthrie +martins +murdoch +194 +tanya +nicely +dolly +lacy +med +##45 +syn +decks +fashionable +millionaire +##ust +surfing +##ml +##ision +heaved +tammy +consulate +attendees +routinely +197 +fuse +saxophonist +backseat +malaya +##lord +scowl +tau +##ishly +193 +sighted +steaming +##rks +303 +911 +##holes +##hong +ching +##wife +bless +conserved +jurassic +stacey +unix +zion +chunk +rigorous +blaine +198 +peabody +slayer +dismay +brewers +nz +##jer +det +##glia +glover +postwar +int +penetration +sylvester +imitation +vertically +airlift +heiress +knoxville +viva +##uin +390 +macon +##rim +##fighter +##gonal +janice +##orescence +##wari +marius +belongings +leicestershire +196 +blanco +inverted +preseason +sanity +sobbing +##due +##elt +##dled +collingwood +regeneration +flickering +shortest +##mount +##osi +feminism +##lat +sherlock +cabinets +fumbled +northbound +precedent +snaps +##mme +researching +##akes +guillaume +insights +manipulated +vapor +neighbour +sap +gangster +frey +f1 +stalking +scarcely +callie +barnett +tendencies +audi +doomed +assessing +slung +panchayat +ambiguous +bartlett +##etto +distributing +violating +wolverhampton +##hetic +swami +histoire +##urus +liable +pounder +groin +hussain +larsen +popping +surprises +##atter +vie +curt +##station +mute +relocate +musicals +authorization +richter +##sef +immortality +tna +bombings +##press +deteriorated +yiddish +##acious +robbed +colchester +cs +pmid +ao +verified +balancing +apostle +swayed +recognizable +oxfordshire +retention +nottinghamshire +contender +judd +invitational +shrimp +uhf +##icient +cleaner +longitudinal +tanker +##mur +acronym +broker +koppen +sundance +suppliers +##gil +4000 +clipped +fuels +petite +##anne +landslide +helene +diversion +populous +landowners +auspices +melville +quantitative +##xes +ferries +nicky +##llus +doo +haunting +roche +carver +downed +unavailable +##pathy +approximation +hiroshima +##hue +garfield +valle +comparatively +keyboardist +traveler +##eit +congestion +calculating +subsidiaries +##bate +serb +modernization +fairies +deepened +ville +averages +##lore +inflammatory +tonga +##itch +co₂ +squads +##hea +gigantic +serum +enjoyment +retailer +verona +35th +cis +##phobic +magna +technicians +##vati +arithmetic +##sport +levin +##dation +amtrak +chow +sienna +##eyer +backstage +entrepreneurship +##otic +learnt +tao +##udy +worcestershire +formulation +baggage +hesitant +bali +sabotage +##kari +barren +enhancing +murmur +pl +freshly +putnam +syntax +aces +medicines +resentment +bandwidth +##sier +grins +chili +guido +##sei +framing +implying +gareth +lissa +genevieve +pertaining +admissions +geo +thorpe +proliferation +sato +bela +analyzing +parting +##gor +awakened +##isman +huddled +secrecy +##kling +hush +gentry +540 +dungeons +##ego +coasts +##utz +sacrificed +##chule +landowner +mutually +prevalence +programmer +adolescent +disrupted +seaside +gee +trusts +vamp +georgie +##nesian +##iol +schedules +sindh +##market +etched +hm +sparse +bey +beaux +scratching +gliding +unidentified +216 +collaborating +gems +jesuits +oro +accumulation +shaping +mbe +anal +##xin +231 +enthusiasts +newscast +##egan +janata +dewey +parkinson +179 +ankara +biennial +towering +dd +inconsistent +950 +##chet +thriving +terminate +cabins +furiously +eats +advocating +donkey +marley +muster +phyllis +leiden +##user +grassland +glittering +iucn +loneliness +217 +memorandum +armenians +##ddle +popularized +rhodesia +60s +lame +##illon +sans +bikini +header +orbits +##xx +##finger +##ulator +sharif +spines +biotechnology +strolled +naughty +yates +##wire +fremantle +milo +##mour +abducted +removes +##atin +humming +wonderland +##chrome +##ester +hume +pivotal +##rates +armand +grams +believers +elector +rte +apron +bis +scraped +##yria +endorsement +initials +##llation +eps +dotted +hints +buzzing +emigration +nearer +##tom +indicators +##ulu +coarse +neutron +protectorate +##uze +directional +exploits +pains +loire +1830s +proponents +guggenheim +rabbits +ritchie +305 +hectare +inputs +hutton +##raz +verify +##ako +boilers +longitude +##lev +skeletal +yer +emilia +citrus +compromised +##gau +pokemon +prescription +paragraph +eduard +cadillac +attire +categorized +kenyan +weddings +charley +##bourg +entertain +monmouth +##lles +nutrients +davey +mesh +incentive +practised +ecosystems +kemp +subdued +overheard +##rya +bodily +maxim +##nius +apprenticeship +ursula +##fight +lodged +rug +silesian +unconstitutional +patel +inspected +coyote +unbeaten +##hak +34th +disruption +convict +parcel +##cl +##nham +collier +implicated +mallory +##iac +##lab +susannah +winkler +##rber +shia +phelps +sediments +graphical +robotic +##sner +adulthood +mart +smoked +##isto +kathryn +clarified +##aran +divides +convictions +oppression +pausing +burying +##mt +federico +mathias +eileen +##tana +kite +hunched +##acies +189 +##atz +disadvantage +liza +kinetic +greedy +paradox +yokohama +dowager +trunks +ventured +##gement +gupta +vilnius +olaf +##thest +crimean +hopper +##ej +progressively +arturo +mouthed +arrondissement +##fusion +rubin +simulcast +oceania +##orum +##stra +##rred +busiest +intensely +navigator +cary +##vine +##hini +##bies +fife +rowe +rowland +posing +insurgents +shafts +lawsuits +activate +conor +inward +culturally +garlic +265 +##eering +eclectic +##hui +##kee +##nl +furrowed +vargas +meteorological +rendezvous +##aus +culinary +commencement +##dition +quota +##notes +mommy +salaries +overlapping +mule +##iology +##mology +sums +wentworth +##isk +##zione +mainline +subgroup +##illy +hack +plaintiff +verdi +bulb +differentiation +engagements +multinational +supplemented +bertrand +caller +regis +##naire +##sler +##arts +##imated +blossom +propagation +kilometer +viaduct +vineyards +##uate +beckett +optimization +golfer +songwriters +seminal +semitic +thud +volatile +evolving +ridley +##wley +trivial +distributions +scandinavia +jiang +##ject +wrestled +insistence +##dio +emphasizes +napkin +##ods +adjunct +rhyme +##ricted +##eti +hopeless +surrounds +tremble +32nd +smoky +##ntly +oils +medicinal +padded +steer +wilkes +219 +255 +concessions +hue +uniquely +blinded +landon +yahoo +##lane +hendrix +commemorating +dex +specify +chicks +##ggio +intercity +1400 +morley +##torm +highlighting +##oting +pang +oblique +stalled +##liner +flirting +newborn +1769 +bishopric +shaved +232 +currie +##ush +dharma +spartan +##ooped +favorites +smug +novella +sirens +abusive +creations +espana +##lage +paradigm +semiconductor +sheen +##rdo +##yen +##zak +nrl +renew +##pose +##tur +adjutant +marches +norma +##enity +ineffective +weimar +grunt +##gat +lordship +plotting +expenditure +infringement +lbs +refrain +av +mimi +mistakenly +postmaster +1771 +##bara +ras +motorsports +tito +199 +subjective +##zza +bully +stew +##kaya +prescott +1a +##raphic +##zam +bids +styling +paranormal +reeve +sneaking +exploding +katz +akbar +migrant +syllables +indefinitely +##ogical +destroys +replaces +applause +##phine +pest +##fide +218 +articulated +bertie +##thing +##cars +##ptic +courtroom +crowley +aesthetics +cummings +tehsil +hormones +titanic +dangerously +##ibe +stadion +jaenelle +auguste +ciudad +##chu +mysore +partisans +##sio +lucan +philipp +##aly +debating +henley +interiors +##rano +##tious +homecoming +beyonce +usher +henrietta +prepares +weeds +##oman +ely +plucked +##pire +##dable +luxurious +##aq +artifact +password +pasture +juno +maddy +minsk +##dder +##ologies +##rone +assessments +martian +royalist +1765 +examines +##mani +##rge +nino +223 +parry +scooped +relativity +##eli +##uting +##cao +congregational +noisy +traverse +##agawa +strikeouts +nickelodeon +obituary +transylvania +binds +depictions +polk +trolley +##yed +##lard +breeders +##under +dryly +hokkaido +1762 +strengths +stacks +bonaparte +connectivity +neared +prostitutes +stamped +anaheim +gutierrez +sinai +##zzling +bram +fresno +madhya +##86 +proton +##lena +##llum +##phon +reelected +wanda +##anus +##lb +ample +distinguishing +##yler +grasping +sermons +tomato +bland +stimulation +avenues +##eux +spreads +scarlett +fern +pentagon +assert +baird +chesapeake +ir +calmed +distortion +fatalities +##olis +correctional +pricing +##astic +##gina +prom +dammit +ying +collaborate +##chia +welterweight +33rd +pointer +substitution +bonded +umpire +communicating +multitude +paddle +##obe +federally +intimacy +##insky +betray +ssr +##lett +##lean +##lves +##therapy +airbus +##tery +functioned +ud +bearer +biomedical +netflix +##hire +##nca +condom +brink +ik +##nical +macy +##bet +flap +gma +experimented +jelly +lavender +##icles +##ulia +munro +##mian +##tial +rye +##rle +60th +gigs +hottest +rotated +predictions +fuji +bu +##erence +##omi +barangay +##fulness +##sas +clocks +##rwood +##liness +cereal +roe +wight +decker +uttered +babu +onion +xml +forcibly +##df +petra +sarcasm +hartley +peeled +storytelling +##42 +##xley +##ysis +##ffa +fibre +kiel +auditor +fig +harald +greenville +##berries +geographically +nell +quartz +##athic +cemeteries +##lr +crossings +nah +holloway +reptiles +chun +sichuan +snowy +660 +corrections +##ivo +zheng +ambassadors +blacksmith +fielded +fluids +hardcover +turnover +medications +melvin +academies +##erton +ro +roach +absorbing +spaniards +colton +##founded +outsider +espionage +kelsey +245 +edible +##ulf +dora +establishes +##sham +##tries +contracting +##tania +cinematic +costello +nesting +##uron +connolly +duff +##nology +mma +##mata +fergus +sexes +gi +optics +spectator +woodstock +banning +##hee +##fle +differentiate +outfielder +refinery +226 +312 +gerhard +horde +lair +drastically +##udi +landfall +##cheng +motorsport +odi +##achi +predominant +quay +skins +##ental +edna +harshly +complementary +murdering +##aves +wreckage +##90 +ono +outstretched +lennox +munitions +galen +reconcile +470 +scalp +bicycles +gillespie +questionable +rosenberg +guillermo +hostel +jarvis +kabul +volvo +opium +yd +##twined +abuses +decca +outpost +##cino +sensible +neutrality +##64 +ponce +anchorage +atkins +turrets +inadvertently +disagree +libre +vodka +reassuring +weighs +##yal +glide +jumper +ceilings +repertory +outs +stain +##bial +envy +##ucible +smashing +heightened +policing +hyun +mixes +lai +prima +##ples +celeste +##bina +lucrative +intervened +kc +manually +##rned +stature +staffed +bun +bastards +nairobi +priced +##auer +thatcher +##kia +tripped +comune +##ogan +##pled +brasil +incentives +emanuel +hereford +musica +##kim +benedictine +biennale +##lani +eureka +gardiner +rb +knocks +sha +##ael +##elled +##onate +efficacy +ventura +masonic +sanford +maize +leverage +##feit +capacities +santana +##aur +novelty +vanilla +##cter +##tour +benin +##oir +##rain +neptune +drafting +tallinn +##cable +humiliation +##boarding +schleswig +fabian +bernardo +liturgy +spectacle +sweeney +pont +routledge +##tment +cosmos +ut +hilt +sleek +universally +##eville +##gawa +typed +##dry +favors +allegheny +glaciers +##rly +recalling +aziz +##log +parasite +requiem +auf +##berto +##llin +illumination +##breaker +##issa +festivities +bows +govern +vibe +vp +333 +sprawled +larson +pilgrim +bwf +leaping +##rts +##ssel +alexei +greyhound +hoarse +##dler +##oration +seneca +##cule +gaping +##ulously +##pura +cinnamon +##gens +##rricular +craven +fantasies +houghton +engined +reigned +dictator +supervising +##oris +bogota +commentaries +unnatural +fingernails +spirituality +tighten +##tm +canadiens +protesting +intentional +cheers +sparta +##ytic +##iere +##zine +widen +belgarath +controllers +dodd +iaaf +navarre +##ication +defect +squire +steiner +whisky +##mins +560 +inevitably +tome +##gold +chew +##uid +##lid +elastic +##aby +streaked +alliances +jailed +regal +##ined +##phy +czechoslovak +narration +absently +##uld +bluegrass +guangdong +quran +criticizing +hose +hari +##liest +##owa +skier +streaks +deploy +##lom +raft +bose +dialed +huff +##eira +haifa +simplest +bursting +endings +ib +sultanate +##titled +franks +whitman +ensures +sven +##ggs +collaborators +forster +organising +ui +banished +napier +injustice +teller +layered +thump +##otti +roc +battleships +evidenced +fugitive +sadie +robotics +##roud +equatorial +geologist +##iza +yielding +##bron +##sr +internationale +mecca +##diment +sbs +skyline +toad +uploaded +reflective +undrafted +lal +leafs +bayern +##dai +lakshmi +shortlisted +##stick +##wicz +camouflage +donate +af +christi +lau +##acio +disclosed +nemesis +1761 +assemble +straining +northamptonshire +tal +##asi +bernardino +premature +heidi +42nd +coefficients +galactic +reproduce +buzzed +sensations +zionist +monsieur +myrtle +##eme +archery +strangled +musically +viewpoint +antiquities +bei +trailers +seahawks +cured +pee +preferring +tasmanian +lange +sul +##mail +##working +colder +overland +lucivar +massey +gatherings +haitian +##smith +disapproval +flaws +##cco +##enbach +1766 +npr +##icular +boroughs +creole +forums +techno +1755 +dent +abdominal +streetcar +##eson +##stream +procurement +gemini +predictable +##tya +acheron +christoph +feeder +fronts +vendor +bernhard +jammu +tumors +slang +##uber +goaltender +twists +curving +manson +vuelta +mer +peanut +confessions +pouch +unpredictable +allowance +theodor +vascular +##factory +bala +authenticity +metabolic +coughing +nanjing +##cea +pembroke +##bard +splendid +36th +ff +hourly +##ahu +elmer +handel +##ivate +awarding +thrusting +dl +experimentation +##hesion +##46 +caressed +entertained +steak +##rangle +biologist +orphans +baroness +oyster +stepfather +##dridge +mirage +reefs +speeding +##31 +barons +1764 +227 +inhabit +preached +repealed +##tral +honoring +boogie +captives +administer +johanna +##imate +gel +suspiciously +1767 +sobs +##dington +backbone +hayward +garry +##folding +##nesia +maxi +##oof +##ppe +ellison +galileo +##stand +crimea +frenzy +amour +bumper +matrices +natalia +baking +garth +palestinians +##grove +smack +conveyed +ensembles +gardening +##manship +##rup +##stituting +1640 +harvesting +topography +jing +shifters +dormitory +##carriage +##lston +ist +skulls +##stadt +dolores +jewellery +sarawak +##wai +##zier +fences +christy +confinement +tumbling +credibility +fir +stench +##bria +##plication +##nged +##sam +virtues +##belt +marjorie +pba +##eem +##made +celebrates +schooner +agitated +barley +fulfilling +anthropologist +##pro +restrict +novi +regulating +##nent +padres +##rani +##hesive +loyola +tabitha +milky +olson +proprietor +crambidae +guarantees +intercollegiate +ljubljana +hilda +##sko +ignorant +hooded +##lts +sardinia +##lidae +##vation +frontman +privileged +witchcraft +##gp +jammed +laude +poking +##than +bracket +amazement +yunnan +##erus +maharaja +linnaeus +264 +commissioning +milano +peacefully +##logies +akira +rani +regulator +##36 +grasses +##rance +luzon +crows +compiler +gretchen +seaman +edouard +tab +buccaneers +ellington +hamlets +whig +socialists +##anto +directorial +easton +mythological +##kr +##vary +rhineland +semantic +taut +dune +inventions +succeeds +##iter +replication +branched +##pired +jul +prosecuted +kangaroo +penetrated +##avian +middlesbrough +doses +bleak +madam +predatory +relentless +##vili +reluctance +##vir +hailey +crore +silvery +1759 +monstrous +swimmers +transmissions +hawthorn +informing +##eral +toilets +caracas +crouch +kb +##sett +295 +cartel +hadley +##aling +alexia +yvonne +##biology +cinderella +eton +superb +blizzard +stabbing +industrialist +maximus +##gm +##orus +groves +maud +clade +oversized +comedic +##bella +rosen +nomadic +fulham +montane +beverages +galaxies +redundant +swarm +##rot +##folia +##llis +buckinghamshire +fen +bearings +bahadur +##rom +gilles +phased +dynamite +faber +benoit +vip +##ount +##wd +booking +fractured +tailored +anya +spices +westwood +cairns +auditions +inflammation +steamed +##rocity +##acion +##urne +skyla +thereof +watford +torment +archdeacon +transforms +lulu +demeanor +fucked +serge +##sor +mckenna +minas +entertainer +##icide +caress +originate +residue +##sty +1740 +##ilised +##org +beech +##wana +subsidies +##ghton +emptied +gladstone +ru +firefighters +voodoo +##rcle +het +nightingale +tamara +edmond +ingredient +weaknesses +silhouette +285 +compatibility +withdrawing +hampson +##mona +anguish +giggling +##mber +bookstore +##jiang +southernmost +tilting +##vance +bai +economical +rf +briefcase +dreadful +hinted +projections +shattering +totaling +##rogate +analogue +indicted +periodical +fullback +##dman +haynes +##tenberg +##ffs +##ishment +1745 +thirst +stumble +penang +vigorous +##ddling +##kor +##lium +octave +##ove +##enstein +##inen +##ones +siberian +##uti +cbn +repeal +swaying +##vington +khalid +tanaka +unicorn +otago +plastered +lobe +riddle +##rella +perch +##ishing +croydon +filtered +graeme +tripoli +##ossa +crocodile +##chers +sufi +mined +##tung +inferno +lsu +##phi +swelled +utilizes +£2 +cale +periodicals +styx +hike +informally +coop +lund +##tidae +ala +hen +qui +transformations +disposed +sheath +chickens +##cade +fitzroy +sas +silesia +unacceptable +odisha +1650 +sabrina +pe +spokane +ratios +athena +massage +shen +dilemma +##drum +##riz +##hul +corona +doubtful +niall +##pha +##bino +fines +cite +acknowledging +bangor +ballard +bathurst +##resh +huron +mustered +alzheimer +garments +kinase +tyre +warship +##cp +flashback +pulmonary +braun +cheat +kamal +cyclists +constructions +grenades +ndp +traveller +excuses +stomped +signalling +trimmed +futsal +mosques +relevance +##wine +wta +##23 +##vah +##lter +hoc +##riding +optimistic +##´s +deco +sim +interacting +rejecting +moniker +waterways +##ieri +##oku +mayors +gdansk +outnumbered +pearls +##ended +##hampton +fairs +totals +dominating +262 +notions +stairway +compiling +pursed +commodities +grease +yeast +##jong +carthage +griffiths +residual +amc +contraction +laird +sapphire +##marine +##ivated +amalgamation +dissolve +inclination +lyle +packaged +altitudes +suez +canons +graded +lurched +narrowing +boasts +guise +wed +enrico +##ovsky +rower +scarred +bree +cub +iberian +protagonists +bargaining +proposing +trainers +voyages +vans +fishes +##aea +##ivist +##verance +encryption +artworks +kazan +sabre +cleopatra +hepburn +rotting +supremacy +mecklenburg +##brate +burrows +hazards +outgoing +flair +organizes +##ctions +scorpion +##usions +boo +234 +chevalier +dunedin +slapping +##34 +ineligible +pensions +##38 +##omic +manufactures +emails +bismarck +238 +weakening +blackish +ding +mcgee +quo +##rling +northernmost +xx +manpower +greed +sampson +clicking +##ange +##horpe +##inations +##roving +torre +##eptive +##moral +symbolism +38th +asshole +meritorious +outfits +splashed +biographies +sprung +astros +##tale +302 +737 +filly +raoul +nw +tokugawa +linden +clubhouse +##apa +tracts +romano +##pio +putin +tags +##note +chained +dickson +gunshot +moe +gunn +rashid +##tails +zipper +##bas +##nea +contrasted +##ply +##udes +plum +pharaoh +##pile +aw +comedies +ingrid +sandwiches +subdivisions +1100 +mariana +nokia +kamen +hz +delaney +veto +herring +##words +possessive +outlines +##roup +siemens +stairwell +rc +gallantry +messiah +palais +yells +233 +zeppelin +##dm +bolivar +##cede +smackdown +mckinley +##mora +##yt +muted +geologic +finely +unitary +avatar +hamas +maynard +rees +bog +contrasting +##rut +liv +chico +disposition +pixel +##erate +becca +dmitry +yeshiva +narratives +##lva +##ulton +mercenary +sharpe +tempered +navigate +stealth +amassed +keynes +##lini +untouched +##rrie +havoc +lithium +##fighting +abyss +graf +southward +wolverine +balloons +implements +ngos +transitions +##icum +ambushed +concacaf +dormant +economists +##dim +costing +csi +rana +universite +boulders +verity +##llon +collin +mellon +misses +cypress +fluorescent +lifeless +spence +##ulla +crewe +shepard +pak +revelations +##م +jolly +gibbons +paw +##dro +##quel +freeing +##test +shack +fries +palatine +##51 +##hiko +accompaniment +cruising +recycled +##aver +erwin +sorting +synthesizers +dyke +realities +sg +strides +enslaved +wetland +##ghan +competence +gunpowder +grassy +maroon +reactors +objection +##oms +carlson +gearbox +macintosh +radios +shelton +##sho +clergyman +prakash +254 +mongols +trophies +oricon +228 +stimuli +twenty20 +cantonese +cortes +mirrored +##saurus +bhp +cristina +melancholy +##lating +enjoyable +nuevo +##wny +downfall +schumacher +##ind +banging +lausanne +rumbled +paramilitary +reflex +ax +amplitude +migratory +##gall +##ups +midi +barnard +lastly +sherry +##hp +##nall +keystone +##kra +carleton +slippery +##53 +coloring +foe +socket +otter +##rgos +mats +##tose +consultants +bafta +bison +topping +##km +490 +primal +abandonment +transplant +atoll +hideous +mort +pained +reproduced +tae +howling +##turn +unlawful +billionaire +hotter +poised +lansing +##chang +dinamo +retro +messing +nfc +domesday +##mina +blitz +timed +##athing +##kley +ascending +gesturing +##izations +signaled +tis +chinatown +mermaid +savanna +jameson +##aint +catalina +##pet +##hers +cochrane +cy +chatting +##kus +alerted +computation +mused +noelle +majestic +mohawk +campo +octagonal +##sant +##hend +241 +aspiring +##mart +comprehend +iona +paralyzed +shimmering +swindon +rhone +##eley +reputed +configurations +pitchfork +agitation +francais +gillian +lipstick +##ilo +outsiders +pontifical +resisting +bitterness +sewer +rockies +##edd +##ucher +misleading +1756 +exiting +galloway +##nging +risked +##heart +246 +commemoration +schultz +##rka +integrating +##rsa +poses +shrieked +##weiler +guineas +gladys +jerking +owls +goldsmith +nightly +penetrating +##unced +lia +##33 +ignited +betsy +##aring +##thorpe +follower +vigorously +##rave +coded +kiran +knit +zoology +tbilisi +##28 +##bered +repository +govt +deciduous +dino +growling +##bba +enhancement +unleashed +chanting +pussy +biochemistry +##eric +kettle +repression +toxicity +nrhp +##arth +##kko +##bush +ernesto +commended +outspoken +242 +mca +parchment +sms +kristen +##aton +bisexual +raked +glamour +navajo +a2 +conditioned +showcased +##hma +spacious +youthful +##esa +usl +appliances +junta +brest +layne +conglomerate +enchanted +chao +loosened +picasso +circulating +inspect +montevideo +##centric +##kti +piazza +spurred +##aith +bari +freedoms +poultry +stamford +lieu +##ect +indigo +sarcastic +bahia +stump +attach +dvds +frankenstein +lille +approx +scriptures +pollen +##script +nmi +overseen +##ivism +tides +proponent +newmarket +inherit +milling +##erland +centralized +##rou +distributors +credentials +drawers +abbreviation +##lco +##xon +downing +uncomfortably +ripe +##oes +erase +franchises +##ever +populace +##bery +##khar +decomposition +pleas +##tet +daryl +sabah +##stle +##wide +fearless +genie +lesions +annette +##ogist +oboe +appendix +nair +dripped +petitioned +maclean +mosquito +parrot +rpg +hampered +1648 +operatic +reservoirs +##tham +irrelevant +jolt +summarized +##fp +medallion +##taff +##− +clawed +harlow +narrower +goddard +marcia +bodied +fremont +suarez +altering +tempest +mussolini +porn +##isms +sweetly +oversees +walkers +solitude +grimly +shrines +hk +ich +supervisors +hostess +dietrich +legitimacy +brushes +expressive +##yp +dissipated +##rse +localized +systemic +##nikov +gettysburg +##js +##uaries +dialogues +muttering +251 +housekeeper +sicilian +discouraged +##frey +beamed +kaladin +halftime +kidnap +##amo +##llet +1754 +synonymous +depleted +instituto +insulin +reprised +##opsis +clashed +##ctric +interrupting +radcliffe +insisting +medici +1715 +ejected +playfully +turbulent +##47 +starvation +##rini +shipment +rebellious +petersen +verification +merits +##rified +cakes +##charged +1757 +milford +shortages +spying +fidelity +##aker +emitted +storylines +harvested +seismic +##iform +cheung +kilda +theoretically +barbie +lynx +##rgy +##tius +goblin +mata +poisonous +##nburg +reactive +residues +obedience +##евич +conjecture +##rac +401 +hating +sixties +kicker +moaning +motown +##bha +emancipation +neoclassical +##hering +consoles +ebert +professorship +##tures +sustaining +assaults +obeyed +affluent +incurred +tornadoes +##eber +##zow +emphasizing +highlanders +cheated +helmets +##ctus +internship +terence +bony +executions +legislators +berries +peninsular +tinged +##aco +1689 +amplifier +corvette +ribbons +lavish +pennant +##lander +worthless +##chfield +##forms +mariano +pyrenees +expenditures +##icides +chesterfield +mandir +tailor +39th +sergey +nestled +willed +aristocracy +devotees +goodnight +raaf +rumored +weaponry +remy +appropriations +harcourt +burr +riaa +##lence +limitation +unnoticed +guo +soaking +swamps +##tica +collapsing +tatiana +descriptive +brigham +psalm +##chment +maddox +##lization +patti +caliph +##aja +akron +injuring +serra +##ganj +basins +##sari +astonished +launcher +##church +hilary +wilkins +sewing +##sf +stinging +##fia +##ncia +underwood +startup +##ition +compilations +vibrations +embankment +jurist +##nity +bard +juventus +groundwater +kern +palaces +helium +boca +cramped +marissa +soto +##worm +jae +princely +##ggy +faso +bazaar +warmly +##voking +229 +pairing +##lite +##grate +##nets +wien +freaked +ulysses +rebirth +##alia +##rent +mummy +guzman +jimenez +stilled +##nitz +trajectory +tha +woken +archival +professions +##pts +##pta +hilly +shadowy +shrink +##bolt +norwood +glued +migrate +stereotypes +devoid +##pheus +625 +evacuate +horrors +infancy +gotham +knowles +optic +downloaded +sachs +kingsley +parramatta +darryl +mor +##onale +shady +commence +confesses +kan +##meter +##placed +marlborough +roundabout +regents +frigates +io +##imating +gothenburg +revoked +carvings +clockwise +convertible +intruder +##sche +banged +##ogo +vicky +bourgeois +##mony +dupont +footing +##gum +pd +##real +buckle +yun +penthouse +sane +720 +serviced +stakeholders +neumann +bb +##eers +comb +##gam +catchment +pinning +rallies +typing +##elles +forefront +freiburg +sweetie +giacomo +widowed +goodwill +worshipped +aspirations +midday +##vat +fishery +##trick +bournemouth +turk +243 +hearth +ethanol +guadalajara +murmurs +sl +##uge +afforded +scripted +##hta +wah +##jn +coroner +translucent +252 +memorials +puck +progresses +clumsy +##race +315 +candace +recounted +##27 +##slin +##uve +filtering +##mac +howl +strata +heron +leveled +##ays +dubious +##oja +##т +##wheel +citations +exhibiting +##laya +##mics +##pods +turkic +##lberg +injunction +##ennial +##mit +antibodies +##44 +organise +##rigues +cardiovascular +cushion +inverness +##zquez +dia +cocoa +sibling +##tman +##roid +expanse +feasible +tunisian +algiers +##relli +rus +bloomberg +dso +westphalia +bro +tacoma +281 +downloads +##ours +konrad +duran +##hdi +continuum +jett +compares +legislator +secession +##nable +##gues +##zuka +translating +reacher +##gley +##ła +aleppo +##agi +tc +orchards +trapping +linguist +versatile +drumming +postage +calhoun +superiors +##mx +barefoot +leary +##cis +ignacio +alfa +kaplan +##rogen +bratislava +mori +##vot +disturb +haas +313 +cartridges +gilmore +radiated +salford +tunic +hades +##ulsive +archeological +delilah +magistrates +auditioned +brewster +charters +empowerment +blogs +cappella +dynasties +iroquois +whipping +##krishna +raceway +truths +myra +weaken +judah +mcgregor +##horse +mic +refueling +37th +burnley +bosses +markus +premio +query +##gga +dunbar +##economic +darkest +lyndon +sealing +commendation +reappeared +##mun +addicted +ezio +slaughtered +satisfactory +shuffle +##eves +##thic +##uj +fortification +warrington +##otto +resurrected +fargo +mane +##utable +##lei +##space +foreword +ox +##aris +##vern +abrams +hua +##mento +sakura +##alo +uv +sentimental +##skaya +midfield +##eses +sturdy +scrolls +macleod +##kyu +entropy +##lance +mitochondrial +cicero +excelled +thinner +convoys +perceive +##oslav +##urable +systematically +grind +burkina +287 +##tagram +ops +##aman +guantanamo +##cloth +##tite +forcefully +wavy +##jou +pointless +##linger +##tze +layton +portico +superficial +clerical +outlaws +##hism +burials +muir +##inn +creditors +hauling +rattle +##leg +calais +monde +archers +reclaimed +dwell +wexford +hellenic +falsely +remorse +##tek +dough +furnishings +##uttered +gabon +neurological +novice +##igraphy +contemplated +pulpit +nightstand +saratoga +##istan +documenting +pulsing +taluk +##firmed +busted +marital +##rien +disagreements +wasps +##yes +hodge +mcdonnell +mimic +fran +pendant +dhabi +musa +##nington +congratulations +argent +darrell +concussion +losers +regrets +thessaloniki +reversal +donaldson +hardwood +thence +achilles +ritter +##eran +demonic +jurgen +prophets +goethe +eki +classmate +buff +##cking +yank +irrational +##inging +perished +seductive +qur +sourced +##crat +##typic +mustard +ravine +barre +horizontally +characterization +phylogenetic +boise +##dit +##runner +##tower +brutally +intercourse +seduce +##bbing +fay +ferris +ogden +amar +nik +unarmed +##inator +evaluating +kyrgyzstan +sweetness +##lford +##oki +mccormick +meiji +notoriety +stimulate +disrupt +figuring +instructional +mcgrath +##zoo +groundbreaking +##lto +flinch +khorasan +agrarian +bengals +mixer +radiating +##sov +ingram +pitchers +nad +tariff +##cript +tata +##codes +##emi +##ungen +appellate +lehigh +##bled +##giri +brawl +duct +texans +##ciation +##ropolis +skipper +speculative +vomit +doctrines +stresses +253 +davy +graders +whitehead +jozef +timely +cumulative +haryana +paints +appropriately +boon +cactus +##ales +##pid +dow +legions +##pit +perceptions +1730 +picturesque +##yse +periphery +rune +wr +##aha +celtics +sentencing +whoa +##erin +confirms +variance +425 +moines +mathews +spade +rave +m1 +fronted +fx +blending +alleging +reared +##gl +237 +##paper +grassroots +eroded +##free +##physical +directs +ordeal +##sław +accelerate +hacker +rooftop +##inia +lev +buys +cebu +devote +##lce +specialising +##ulsion +choreographed +repetition +warehouses +##ryl +paisley +tuscany +analogy +sorcerer +hash +huts +shards +descends +exclude +nix +chaplin +gaga +ito +vane +##drich +causeway +misconduct +limo +orchestrated +glands +jana +##kot +u2 +##mple +##sons +branching +contrasts +scoop +longed +##virus +chattanooga +##75 +syrup +cornerstone +##tized +##mind +##iaceae +careless +precedence +frescoes +##uet +chilled +consult +modelled +snatch +peat +##thermal +caucasian +humane +relaxation +spins +temperance +##lbert +occupations +lambda +hybrids +moons +mp3 +##oese +247 +rolf +societal +yerevan +ness +##ssler +befriended +mechanized +nominate +trough +boasted +cues +seater +##hom +bends +##tangle +conductors +emptiness +##lmer +eurasian +adriatic +tian +##cie +anxiously +lark +propellers +chichester +jock +ev +2a +##holding +credible +recounts +tori +loyalist +abduction +##hoot +##redo +nepali +##mite +ventral +tempting +##ango +##crats +steered +##wice +javelin +dipping +laborers +prentice +looming +titanium +##ː +badges +emir +tensor +##ntation +egyptians +rash +denies +hawthorne +lombard +showers +wehrmacht +dietary +trojan +##reus +welles +executing +horseshoe +lifeboat +##lak +elsa +infirmary +nearing +roberta +boyer +mutter +trillion +joanne +##fine +##oked +sinks +vortex +uruguayan +clasp +sirius +##block +accelerator +prohibit +sunken +byu +chronological +diplomats +ochreous +510 +symmetrical +1644 +maia +##tology +salts +reigns +atrocities +##ия +hess +bared +issn +##vyn +cater +saturated +##cycle +##isse +sable +voyager +dyer +yusuf +##inge +fountains +wolff +##39 +##nni +engraving +rollins +atheist +ominous +##ault +herr +chariot +martina +strung +##fell +##farlane +horrific +sahib +gazes +saetan +erased +ptolemy +##olic +flushing +lauderdale +analytic +##ices +530 +navarro +beak +gorilla +herrera +broom +guadalupe +raiding +sykes +311 +bsc +deliveries +1720 +invasions +carmichael +tajikistan +thematic +ecumenical +sentiments +onstage +##rians +##brand +##sume +catastrophic +flanks +molten +##arns +waller +aimee +terminating +##icing +alternately +##oche +nehru +printers +outraged +##eving +empires +template +banners +repetitive +za +##oise +vegetarian +##tell +guiana +opt +cavendish +lucknow +synthesized +##hani +##mada +finalized +##ctable +fictitious +mayoral +unreliable +##enham +embracing +peppers +rbis +##chio +##neo +inhibition +slashed +togo +orderly +embroidered +safari +salty +236 +barron +benito +totaled +##dak +pubs +simulated +caden +devin +tolkien +momma +welding +sesame +##ept +gottingen +hardness +630 +shaman +temeraire +620 +adequately +pediatric +##kit +ck +assertion +radicals +composure +cadence +seafood +beaufort +lazarus +mani +warily +cunning +kurdistan +249 +cantata +##kir +ares +##41 +##clusive +nape +townland +geared +insulted +flutter +boating +violate +draper +dumping +malmo +##hh +##romatic +firearm +alta +bono +obscured +##clave +exceeds +panorama +unbelievable +##train +preschool +##essed +disconnected +installing +rescuing +secretaries +accessibility +##castle +##drive +##ifice +##film +bouts +slug +waterway +mindanao +##buro +##ratic +halves +##ل +calming +liter +maternity +adorable +bragg +electrification +mcc +##dote +roxy +schizophrenia +##body +munoz +kaye +whaling +239 +mil +tingling +tolerant +##ago +unconventional +volcanoes +##finder +deportivo +##llie +robson +kaufman +neuroscience +wai +deportation +masovian +scraping +converse +##bh +hacking +bulge +##oun +administratively +yao +580 +amp +mammoth +booster +claremont +hooper +nomenclature +pursuits +mclaughlin +melinda +##sul +catfish +barclay +substrates +taxa +zee +originals +kimberly +packets +padma +##ality +borrowing +ostensibly +solvent +##bri +##genesis +##mist +lukas +shreveport +veracruz +##ь +##lou +##wives +cheney +tt +anatolia +hobbs +##zyn +cyclic +radiant +alistair +greenish +siena +dat +independents +##bation +conform +pieter +hyper +applicant +bradshaw +spores +telangana +vinci +inexpensive +nuclei +322 +jang +nme +soho +spd +##ign +cradled +receptionist +pow +##43 +##rika +fascism +##ifer +experimenting +##ading +##iec +##region +345 +jocelyn +maris +stair +nocturnal +toro +constabulary +elgin +##kker +msc +##giving +##schen +##rase +doherty +doping +sarcastically +batter +maneuvers +##cano +##apple +##gai +##git +intrinsic +##nst +##stor +1753 +showtime +cafes +gasps +lviv +ushered +##thed +fours +restart +astonishment +transmitting +flyer +shrugs +##sau +intriguing +cones +dictated +mushrooms +medial +##kovsky +##elman +escorting +gaped +##26 +godfather +##door +##sell +djs +recaptured +timetable +vila +1710 +3a +aerodrome +mortals +scientology +##orne +angelina +mag +convection +unpaid +insertion +intermittent +lego +##nated +endeavor +kota +pereira +##lz +304 +bwv +glamorgan +insults +agatha +fey +##cend +fleetwood +mahogany +protruding +steamship +zeta +##arty +mcguire +suspense +##sphere +advising +urges +##wala +hurriedly +meteor +gilded +inline +arroyo +stalker +##oge +excitedly +revered +##cure +earle +introductory +##break +##ilde +mutants +puff +pulses +reinforcement +##haling +curses +lizards +stalk +correlated +##fixed +fallout +macquarie +##unas +bearded +denton +heaving +802 +##ocation +winery +assign +dortmund +##lkirk +everest +invariant +charismatic +susie +##elling +bled +lesley +telegram +sumner +bk +##ogen +##к +wilcox +needy +colbert +duval +##iferous +##mbled +allotted +attends +imperative +##hita +replacements +hawker +##inda +insurgency +##zee +##eke +casts +##yla +680 +ives +transitioned +##pack +##powering +authoritative +baylor +flex +cringed +plaintiffs +woodrow +##skie +drastic +ape +aroma +unfolded +commotion +nt +preoccupied +theta +routines +lasers +privatization +wand +domino +ek +clenching +nsa +strategically +showered +bile +handkerchief +pere +storing +christophe +insulting +316 +nakamura +romani +asiatic +magdalena +palma +cruises +stripping +405 +konstantin +soaring +##berman +colloquially +forerunner +havilland +incarcerated +parasites +sincerity +##utus +disks +plank +saigon +##ining +corbin +homo +ornaments +powerhouse +##tlement +chong +fastened +feasibility +idf +morphological +usable +##nish +##zuki +aqueduct +jaguars +keepers +##flies +aleksandr +faust +assigns +ewing +bacterium +hurled +tricky +hungarians +integers +wallis +321 +yamaha +##isha +hushed +oblivion +aviator +evangelist +friars +##eller +monograph +ode +##nary +airplanes +labourers +charms +##nee +1661 +hagen +tnt +rudder +fiesta +transcript +dorothea +ska +inhibitor +maccabi +retorted +raining +encompassed +clauses +menacing +1642 +lineman +##gist +vamps +##ape +##dick +gloom +##rera +dealings +easing +seekers +##nut +##pment +helens +unmanned +##anu +##isson +basics +##amy +##ckman +adjustments +1688 +brutality +horne +##zell +sui +##55 +##mable +aggregator +##thal +rhino +##drick +##vira +counters +zoom +##01 +##rting +mn +montenegrin +packard +##unciation +##♭ +##kki +reclaim +scholastic +thugs +pulsed +##icia +syriac +quan +saddam +banda +kobe +blaming +buddies +dissent +##lusion +##usia +corbett +jaya +delle +erratic +lexie +##hesis +435 +amiga +hermes +##pressing +##leen +chapels +gospels +jamal +##uating +compute +revolving +warp +##sso +##thes +armory +##eras +##gol +antrim +loki +##kow +##asian +##good +##zano +braid +handwriting +subdistrict +funky +pantheon +##iculate +concurrency +estimation +improper +juliana +##his +newcomers +johnstone +staten +communicated +##oco +##alle +sausage +stormy +##stered +##tters +superfamily +##grade +acidic +collateral +tabloid +##oped +##rza +bladder +austen +##ellant +mcgraw +##hay +hannibal +mein +aquino +lucifer +wo +badger +boar +cher +christensen +greenberg +interruption +##kken +jem +244 +mocked +bottoms +cambridgeshire +##lide +sprawling +##bbly +eastwood +ghent +synth +##buck +advisers +##bah +nominally +hapoel +qu +daggers +estranged +fabricated +towels +vinnie +wcw +misunderstanding +anglia +nothin +unmistakable +##dust +##lova +chilly +marquette +truss +##edge +##erine +reece +##lty +##chemist +##connected +272 +308 +41st +bash +raion +waterfalls +##ump +##main +labyrinth +queue +theorist +##istle +bharatiya +flexed +soundtracks +rooney +leftist +patrolling +wharton +plainly +alleviate +eastman +schuster +topographic +engages +immensely +unbearable +fairchild +1620 +dona +lurking +parisian +oliveira +ia +indictment +hahn +bangladeshi +##aster +vivo +##uming +##ential +antonia +expects +indoors +kildare +harlan +##logue +##ogenic +##sities +forgiven +##wat +childish +tavi +##mide +##orra +plausible +grimm +successively +scooted +##bola +##dget +##rith +spartans +emery +flatly +azure +epilogue +##wark +flourish +##iny +##tracted +##overs +##oshi +bestseller +distressed +receipt +spitting +hermit +topological +##cot +drilled +subunit +francs +##layer +eel +##fk +##itas +octopus +footprint +petitions +ufo +##say +##foil +interfering +leaking +palo +##metry +thistle +valiant +##pic +narayan +mcpherson +##fast +gonzales +##ym +##enne +dustin +novgorod +solos +##zman +doin +##raph +##patient +##meyer +soluble +ashland +cuffs +carole +pendleton +whistling +vassal +##river +deviation +revisited +constituents +rallied +rotate +loomed +##eil +##nting +amateurs +augsburg +auschwitz +crowns +skeletons +##cona +bonnet +257 +dummy +globalization +simeon +sleeper +mandal +differentiated +##crow +##mare +milne +bundled +exasperated +talmud +owes +segregated +##feng +##uary +dentist +piracy +props +##rang +devlin +##torium +malicious +paws +##laid +dependency +##ergy +##fers +##enna +258 +pistons +rourke +jed +grammatical +tres +maha +wig +512 +ghostly +jayne +##achal +##creen +##ilis +##lins +##rence +designate +##with +arrogance +cambodian +clones +showdown +throttle +twain +##ception +lobes +metz +nagoya +335 +braking +##furt +385 +roaming +##minster +amin +crippled +##37 +##llary +indifferent +hoffmann +idols +intimidating +1751 +261 +influenza +memo +onions +1748 +bandage +consciously +##landa +##rage +clandestine +observes +swiped +tangle +##ener +##jected +##trum +##bill +##lta +hugs +congresses +josiah +spirited +##dek +humanist +managerial +filmmaking +inmate +rhymes +debuting +grimsby +ur +##laze +duplicate +vigor +##tf +republished +bolshevik +refurbishment +antibiotics +martini +methane +newscasts +royale +horizons +levant +iain +visas +##ischen +paler +##around +manifestation +snuck +alf +chop +futile +pedestal +rehab +##kat +bmg +kerman +res +fairbanks +jarrett +abstraction +saharan +##zek +1746 +procedural +clearer +kincaid +sash +luciano +##ffey +crunch +helmut +##vara +revolutionaries +##tute +creamy +leach +##mmon +1747 +permitting +nes +plight +wendell +##lese +contra +ts +clancy +ipa +mach +staples +autopsy +disturbances +nueva +karin +pontiac +##uding +proxy +venerable +haunt +leto +bergman +expands +##helm +wal +##pipe +canning +celine +cords +obesity +##enary +intrusion +planner +##phate +reasoned +sequencing +307 +harrow +##chon +##dora +marred +mcintyre +repay +tarzan +darting +248 +harrisburg +margarita +repulsed +##hur +##lding +belinda +hamburger +novo +compliant +runways +bingham +registrar +skyscraper +ic +cuthbert +improvisation +livelihood +##corp +##elial +admiring +##dened +sporadic +believer +casablanca +popcorn +##29 +asha +shovel +##bek +##dice +coiled +tangible +##dez +casper +elsie +resin +tenderness +rectory +##ivision +avail +sonar +##mori +boutique +##dier +guerre +bathed +upbringing +vaulted +sandals +blessings +##naut +##utnant +1680 +306 +foxes +pia +corrosion +hesitantly +confederates +crystalline +footprints +shapiro +tirana +valentin +drones +45th +microscope +shipments +texted +inquisition +wry +guernsey +unauthorized +resigning +760 +ripple +schubert +stu +reassure +felony +##ardo +brittle +koreans +##havan +##ives +dun +implicit +tyres +##aldi +##lth +magnolia +##ehan +##puri +##poulos +aggressively +fei +gr +familiarity +##poo +indicative +##trust +fundamentally +jimmie +overrun +395 +anchors +moans +##opus +britannia +armagh +##ggle +purposely +seizing +##vao +bewildered +mundane +avoidance +cosmopolitan +geometridae +quartermaster +caf +415 +chatter +engulfed +gleam +purge +##icate +juliette +jurisprudence +guerra +revisions +##bn +casimir +brew +##jm +1749 +clapton +cloudy +conde +hermitage +278 +simulations +torches +vincenzo +matteo +##rill +hidalgo +booming +westbound +accomplishment +tentacles +unaffected +##sius +annabelle +flopped +sloping +##litz +dreamer +interceptor +vu +##loh +consecration +copying +messaging +breaker +climates +hospitalized +1752 +torino +afternoons +winfield +witnessing +##teacher +breakers +choirs +sawmill +coldly +##ege +sipping +haste +uninhabited +conical +bibliography +pamphlets +severn +edict +##oca +deux +illnesses +grips +##pl +rehearsals +sis +thinkers +tame +##keepers +1690 +acacia +reformer +##osed +##rys +shuffling +##iring +##shima +eastbound +ionic +rhea +flees +littered +##oum +rocker +vomiting +groaning +champ +overwhelmingly +civilizations +paces +sloop +adoptive +##tish +skaters +##vres +aiding +mango +##joy +nikola +shriek +##ignon +pharmaceuticals +##mg +tuna +calvert +gustavo +stocked +yearbook +##urai +##mana +computed +subsp +riff +hanoi +kelvin +hamid +moors +pastures +summons +jihad +nectar +##ctors +bayou +untitled +pleasing +vastly +republics +intellect +##η +##ulio +##tou +crumbling +stylistic +sb +##ی +consolation +frequented +h₂o +walden +widows +##iens +404 +##ignment +chunks +improves +288 +grit +recited +##dev +snarl +sociological +##arte +##gul +inquired +##held +bruise +clube +consultancy +homogeneous +hornets +multiplication +pasta +prick +savior +##grin +##kou +##phile +yoon +##gara +grimes +vanishing +cheering +reacting +bn +distillery +##quisite +##vity +coe +dockyard +massif +##jord +escorts +voss +##valent +byte +chopped +hawke +illusions +workings +floats +##koto +##vac +kv +annapolis +madden +##onus +alvaro +noctuidae +##cum +##scopic +avenge +steamboat +forte +illustrates +erika +##trip +570 +dew +nationalities +bran +manifested +thirsty +diversified +muscled +reborn +##standing +arson +##lessness +##dran +##logram +##boys +##kushima +##vious +willoughby +##phobia +286 +alsace +dashboard +yuki +##chai +granville +myspace +publicized +tricked +##gang +adjective +##ater +relic +reorganisation +enthusiastically +indications +saxe +##lassified +consolidate +iec +padua +helplessly +ramps +renaming +regulars +pedestrians +accents +convicts +inaccurate +lowers +mana +##pati +barrie +bjp +outta +someplace +berwick +flanking +invoked +marrow +sparsely +excerpts +clothed +rei +##ginal +wept +##straße +##vish +alexa +excel +##ptive +membranes +aquitaine +creeks +cutler +sheppard +implementations +ns +##dur +fragrance +budge +concordia +magnesium +marcelo +##antes +gladly +vibrating +##rral +##ggles +montrose +##omba +lew +seamus +1630 +cocky +##ament +##uen +bjorn +##rrick +fielder +fluttering +##lase +methyl +kimberley +mcdowell +reductions +barbed +##jic +##tonic +aeronautical +condensed +distracting +##promising +huffed +##cala +##sle +claudius +invincible +missy +pious +balthazar +ci +##lang +butte +combo +orson +##dication +myriad +1707 +silenced +##fed +##rh +coco +netball +yourselves +##oza +clarify +heller +peg +durban +etudes +offender +roast +blackmail +curvature +##woods +vile +309 +illicit +suriname +##linson +overture +1685 +bubbling +gymnast +tucking +##mming +##ouin +maldives +##bala +gurney +##dda +##eased +##oides +backside +pinto +jars +racehorse +tending +##rdial +baronetcy +wiener +duly +##rke +barbarian +cupping +flawed +##thesis +bertha +pleistocene +puddle +swearing +##nob +##tically +fleeting +prostate +amulet +educating +##mined +##iti +##tler +75th +jens +respondents +analytics +cavaliers +papacy +raju +##iente +##ulum +##tip +funnel +271 +disneyland +##lley +sociologist +##iam +2500 +faulkner +louvre +menon +##dson +276 +##ower +afterlife +mannheim +peptide +referees +comedians +meaningless +##anger +##laise +fabrics +hurley +renal +sleeps +##bour +##icle +breakout +kristin +roadside +animator +clover +disdain +unsafe +redesign +##urity +firth +barnsley +portage +reset +narrows +268 +commandos +expansive +speechless +tubular +##lux +essendon +eyelashes +smashwords +##yad +##bang +##claim +craved +sprinted +chet +somme +astor +wrocław +orton +266 +bane +##erving +##uing +mischief +##amps +##sund +scaling +terre +##xious +impairment +offenses +undermine +moi +soy +contiguous +arcadia +inuit +seam +##tops +macbeth +rebelled +##icative +##iot +590 +elaborated +frs +uniformed +##dberg +259 +powerless +priscilla +stimulated +980 +qc +arboretum +frustrating +trieste +bullock +##nified +enriched +glistening +intern +##adia +locus +nouvelle +ollie +ike +lash +starboard +ee +tapestry +headlined +hove +rigged +##vite +pollock +##yme +thrive +clustered +cas +roi +gleamed +olympiad +##lino +pressured +regimes +##hosis +##lick +ripley +##ophone +kickoff +gallon +rockwell +##arable +crusader +glue +revolutions +scrambling +1714 +grover +##jure +englishman +aztec +263 +contemplating +coven +ipad +preach +triumphant +tufts +##esian +rotational +##phus +328 +falkland +##brates +strewn +clarissa +rejoin +environmentally +glint +banded +drenched +moat +albanians +johor +rr +maestro +malley +nouveau +shaded +taxonomy +v6 +adhere +bunk +airfields +##ritan +1741 +encompass +remington +tran +##erative +amelie +mazda +friar +morals +passions +##zai +breadth +vis +##hae +argus +burnham +caressing +insider +rudd +##imov +##mini +##rso +italianate +murderous +textual +wainwright +armada +bam +weave +timer +##taken +##nh +fra +##crest +ardent +salazar +taps +tunis +##ntino +allegro +gland +philanthropic +##chester +implication +##optera +esq +judas +noticeably +wynn +##dara +inched +indexed +crises +villiers +bandit +royalties +patterned +cupboard +interspersed +accessory +isla +kendrick +entourage +stitches +##esthesia +headwaters +##ior +interlude +distraught +draught +1727 +##basket +biased +sy +transient +triad +subgenus +adapting +kidd +shortstop +##umatic +dimly +spiked +mcleod +reprint +nellie +pretoria +windmill +##cek +singled +##mps +273 +reunite +##orous +747 +bankers +outlying +##omp +##ports +##tream +apologies +cosmetics +patsy +##deh +##ocks +##yson +bender +nantes +serene +##nad +lucha +mmm +323 +##cius +##gli +cmll +coinage +nestor +juarez +##rook +smeared +sprayed +twitching +sterile +irina +embodied +juveniles +enveloped +miscellaneous +cancers +dq +gulped +luisa +crested +swat +donegal +ref +##anov +##acker +hearst +mercantile +##lika +doorbell +ua +vicki +##alla +##som +bilbao +psychologists +stryker +sw +horsemen +turkmenistan +wits +##national +anson +mathew +screenings +##umb +rihanna +##agne +##nessy +aisles +##iani +##osphere +hines +kenton +saskatoon +tasha +truncated +##champ +##itan +mildred +advises +fredrik +interpreting +inhibitors +##athi +spectroscopy +##hab +##kong +karim +panda +##oia +##nail +##vc +conqueror +kgb +leukemia +##dity +arrivals +cheered +pisa +phosphorus +shielded +##riated +mammal +unitarian +urgently +chopin +sanitary +##mission +spicy +drugged +hinges +##tort +tipping +trier +impoverished +westchester +##caster +267 +epoch +nonstop +##gman +##khov +aromatic +centrally +cerro +##tively +##vio +billions +modulation +sedimentary +283 +facilitating +outrageous +goldstein +##eak +##kt +ld +maitland +penultimate +pollard +##dance +fleets +spaceship +vertebrae +##nig +alcoholism +als +recital +##bham +##ference +##omics +m2 +##bm +trois +##tropical +##в +commemorates +##meric +marge +##raction +1643 +670 +cosmetic +ravaged +##ige +catastrophe +eng +##shida +albrecht +arterial +bellamy +decor +harmon +##rde +bulbs +synchronized +vito +easiest +shetland +shielding +wnba +##glers +##ssar +##riam +brianna +cumbria +##aceous +##rard +cores +thayer +##nsk +brood +hilltop +luminous +carts +keynote +larkin +logos +##cta +##ا +##mund +##quay +lilith +tinted +277 +wrestle +mobilization +##uses +sequential +siam +bloomfield +takahashi +274 +##ieving +presenters +ringo +blazed +witty +##oven +##ignant +devastation +haydn +harmed +newt +therese +##peed +gershwin +molina +rabbis +sudanese +001 +innate +restarted +##sack +##fus +slices +wb +##shah +enroll +hypothetical +hysterical +1743 +fabio +indefinite +warped +##hg +exchanging +525 +unsuitable +##sboro +gallo +1603 +bret +cobalt +homemade +##hunter +mx +operatives +##dhar +terraces +durable +latch +pens +whorls +##ctuated +##eaux +billing +ligament +succumbed +##gly +regulators +spawn +##brick +##stead +filmfare +rochelle +##nzo +1725 +circumstance +saber +supplements +##nsky +##tson +crowe +wellesley +carrot +##9th +##movable +primate +drury +sincerely +topical +##mad +##rao +callahan +kyiv +smarter +tits +undo +##yeh +announcements +anthologies +barrio +nebula +##islaus +##shaft +##tyn +bodyguards +2021 +assassinate +barns +emmett +scully +##mah +##yd +##eland +##tino +##itarian +demoted +gorman +lashed +prized +adventist +writ +##gui +alla +invertebrates +##ausen +1641 +amman +1742 +align +healy +redistribution +##gf +##rize +insulation +##drop +adherents +hezbollah +vitro +ferns +yanking +269 +php +registering +uppsala +cheerleading +confines +mischievous +tully +##ross +49th +docked +roam +stipulated +pumpkin +##bry +prompt +##ezer +blindly +shuddering +craftsmen +frail +scented +katharine +scramble +shaggy +sponge +helix +zaragoza +279 +##52 +43rd +backlash +fontaine +seizures +posse +cowan +nonfiction +telenovela +wwii +hammered +undone +##gpur +encircled +irs +##ivation +artefacts +oneself +searing +smallpox +##belle +##osaurus +shandong +breached +upland +blushing +rankin +infinitely +psyche +tolerated +docking +evicted +##col +unmarked +##lving +gnome +lettering +litres +musique +##oint +benevolent +##jal +blackened +##anna +mccall +racers +tingle +##ocene +##orestation +introductions +radically +292 +##hiff +##باد +1610 +1739 +munchen +plead +##nka +condo +scissors +##sight +##tens +apprehension +##cey +##yin +hallmark +watering +formulas +sequels +##llas +aggravated +bae +commencing +##building +enfield +prohibits +marne +vedic +civilized +euclidean +jagger +beforehand +blasts +dumont +##arney +##nem +740 +conversions +hierarchical +rios +simulator +##dya +##lellan +hedges +oleg +thrusts +shadowed +darby +maximize +1744 +gregorian +##nded +##routed +sham +unspecified +##hog +emory +factual +##smo +##tp +fooled +##rger +ortega +wellness +marlon +##oton +##urance +casket +keating +ley +enclave +##ayan +char +influencing +jia +##chenko +412 +ammonia +erebidae +incompatible +violins +cornered +##arat +grooves +astronauts +columbian +rampant +fabrication +kyushu +mahmud +vanish +##dern +mesopotamia +##lete +ict +##rgen +caspian +kenji +pitted +##vered +999 +grimace +roanoke +tchaikovsky +twinned +##analysis +##awan +xinjiang +arias +clemson +kazakh +sizable +1662 +##khand +##vard +plunge +tatum +vittorio +##nden +cholera +##dana +##oper +bracing +indifference +projectile +superliga +##chee +realises +upgrading +299 +porte +retribution +##vies +nk +stil +##resses +ama +bureaucracy +blackberry +bosch +testosterone +collapses +greer +##pathic +ioc +fifties +malls +##erved +bao +baskets +adolescents +siegfried +##osity +##tosis +mantra +detecting +existent +fledgling +##cchi +dissatisfied +gan +telecommunication +mingled +sobbed +6000 +controversies +outdated +taxis +##raus +fright +slams +##lham +##fect +##tten +detectors +fetal +tanned +##uw +fray +goth +olympian +skipping +mandates +scratches +sheng +unspoken +hyundai +tracey +hotspur +restrictive +##buch +americana +mundo +##bari +burroughs +diva +vulcan +##6th +distinctions +thumping +##ngen +mikey +sheds +fide +rescues +springsteen +vested +valuation +##ece +##ely +pinnacle +rake +sylvie +##edo +almond +quivering +##irus +alteration +faltered +##wad +51st +hydra +ticked +##kato +recommends +##dicated +antigua +arjun +stagecoach +wilfred +trickle +pronouns +##pon +aryan +nighttime +##anian +gall +pea +stitch +##hei +leung +milos +##dini +eritrea +nexus +starved +snowfall +kant +parasitic +cot +discus +hana +strikers +appleton +kitchens +##erina +##partisan +##itha +##vius +disclose +metis +##channel +1701 +tesla +##vera +fitch +1735 +blooded +##tila +decimal +##tang +##bai +cyclones +eun +bottled +peas +pensacola +basha +bolivian +crabs +boil +lanterns +partridge +roofed +1645 +necks +##phila +opined +patting +##kla +##lland +chuckles +volta +whereupon +##nche +devout +euroleague +suicidal +##dee +inherently +involuntary +knitting +nasser +##hide +puppets +colourful +courageous +southend +stills +miraculous +hodgson +richer +rochdale +ethernet +greta +uniting +prism +umm +##haya +##itical +##utation +deterioration +pointe +prowess +##ropriation +lids +scranton +billings +subcontinent +##koff +##scope +brute +kellogg +psalms +degraded +##vez +stanisław +##ructured +ferreira +pun +astonishing +gunnar +##yat +arya +prc +gottfried +##tight +excursion +##ographer +dina +##quil +##nare +huffington +illustrious +wilbur +gundam +verandah +##zard +naacp +##odle +constructive +fjord +kade +##naud +generosity +thrilling +baseline +cayman +frankish +plastics +accommodations +zoological +##fting +cedric +qb +motorized +##dome +##otted +squealed +tackled +canucks +budgets +situ +asthma +dail +gabled +grasslands +whimpered +writhing +judgments +##65 +minnie +pv +##carbon +bananas +grille +domes +monique +odin +maguire +markham +tierney +##estra +##chua +libel +poke +speedy +atrium +laval +notwithstanding +##edly +fai +kala +##sur +robb +##sma +listings +luz +supplementary +tianjin +##acing +enzo +jd +ric +scanner +croats +transcribed +##49 +arden +cv +##hair +##raphy +##lver +##uy +357 +seventies +staggering +alam +horticultural +hs +regression +timbers +blasting +##ounded +montagu +manipulating +##cit +catalytic +1550 +troopers +##meo +condemnation +fitzpatrick +##oire +##roved +inexperienced +1670 +castes +##lative +outing +314 +dubois +flicking +quarrel +ste +learners +1625 +iq +whistled +##class +282 +classify +tariffs +temperament +355 +folly +liszt +##yles +immersed +jordanian +ceasefire +apparel +extras +maru +fished +##bio +harta +stockport +assortment +craftsman +paralysis +transmitters +##cola +blindness +##wk +fatally +proficiency +solemnly +##orno +repairing +amore +groceries +ultraviolet +##chase +schoolhouse +##tua +resurgence +nailed +##otype +##× +ruse +saliva +diagrams +##tructing +albans +rann +thirties +1b +antennas +hilarious +cougars +paddington +stats +##eger +breakaway +ipod +reza +authorship +prohibiting +scoffed +##etz +##ttle +conscription +defected +trondheim +##fires +ivanov +keenan +##adan +##ciful +##fb +##slow +locating +##ials +##tford +cadiz +basalt +blankly +interned +rags +rattling +##tick +carpathian +reassured +sync +bum +guildford +iss +staunch +##onga +astronomers +sera +sofie +emergencies +susquehanna +##heard +duc +mastery +vh1 +williamsburg +bayer +buckled +craving +##khan +##rdes +bloomington +##write +alton +barbecue +##bians +justine +##hri +##ndt +delightful +smartphone +newtown +photon +retrieval +peugeot +hissing +##monium +##orough +flavors +lighted +relaunched +tainted +##games +##lysis +anarchy +microscopic +hopping +adept +evade +evie +##beau +inhibit +sinn +adjustable +hurst +intuition +wilton +cisco +44th +lawful +lowlands +stockings +thierry +##dalen +##hila +##nai +fates +prank +tb +maison +lobbied +provocative +1724 +4a +utopia +##qual +carbonate +gujarati +purcell +##rford +curtiss +##mei +overgrown +arenas +mediation +swallows +##rnik +respectful +turnbull +##hedron +##hope +alyssa +ozone +##ʻi +ami +gestapo +johansson +snooker +canteen +cuff +declines +empathy +stigma +##ags +##iner +##raine +taxpayers +gui +volga +##wright +##copic +lifespan +overcame +tattooed +enactment +giggles +##ador +##camp +barrington +bribe +obligatory +orbiting +peng +##enas +elusive +sucker +##vating +cong +hardship +empowered +anticipating +estrada +cryptic +greasy +detainees +planck +sudbury +plaid +dod +marriott +kayla +##ears +##vb +##zd +mortally +##hein +cognition +radha +319 +liechtenstein +meade +richly +argyle +harpsichord +liberalism +trumpets +lauded +tyrant +salsa +tiled +lear +promoters +reused +slicing +trident +##chuk +##gami +##lka +cantor +checkpoint +##points +gaul +leger +mammalian +##tov +##aar +##schaft +doha +frenchman +nirvana +##vino +delgado +headlining +##eron +##iography +jug +tko +1649 +naga +intersections +##jia +benfica +nawab +##suka +ashford +gulp +##deck +##vill +##rug +brentford +frazier +pleasures +dunne +potsdam +shenzhen +dentistry +##tec +flanagan +##dorff +##hear +chorale +dinah +prem +quezon +##rogated +relinquished +sutra +terri +##pani +flaps +##rissa +poly +##rnet +homme +aback +##eki +linger +womb +##kson +##lewood +doorstep +orthodoxy +threaded +westfield +##rval +dioceses +fridays +subsided +##gata +loyalists +##biotic +##ettes +letterman +lunatic +prelate +tenderly +invariably +souza +thug +winslow +##otide +furlongs +gogh +jeopardy +##runa +pegasus +##umble +humiliated +standalone +tagged +##roller +freshmen +klan +##bright +attaining +initiating +transatlantic +logged +viz +##uance +1723 +combatants +intervening +stephane +chieftain +despised +grazed +317 +cdc +galveston +godzilla +macro +simulate +##planes +parades +##esses +960 +##ductive +##unes +equator +overdose +##cans +##hosh +##lifting +joshi +epstein +sonora +treacherous +aquatics +manchu +responsive +##sation +supervisory +##christ +##llins +##ibar +##balance +##uso +kimball +karlsruhe +mab +##emy +ignores +phonetic +reuters +spaghetti +820 +almighty +danzig +rumbling +tombstone +designations +lured +outset +##felt +supermarkets +##wt +grupo +kei +kraft +susanna +##blood +comprehension +genealogy +##aghan +##verted +redding +##ythe +1722 +bowing +##pore +##roi +lest +sharpened +fulbright +valkyrie +sikhs +##unds +swans +bouquet +merritt +##tage +##venting +commuted +redhead +clerks +leasing +cesare +dea +hazy +##vances +fledged +greenfield +servicemen +##gical +armando +blackout +dt +sagged +downloadable +intra +potion +pods +##4th +##mism +xp +attendants +gambia +stale +##ntine +plump +asteroids +rediscovered +buds +flea +hive +##neas +1737 +classifications +debuts +##eles +olympus +scala +##eurs +##gno +##mute +hummed +sigismund +visuals +wiggled +await +pilasters +clench +sulfate +##ances +bellevue +enigma +trainee +snort +##sw +clouded +denim +##rank +##rder +churning +hartman +lodges +riches +sima +##missible +accountable +socrates +regulates +mueller +##cr +1702 +avoids +solids +himalayas +nutrient +pup +##jevic +squat +fades +nec +##lates +##pina +##rona +##ου +privateer +tequila +##gative +##mpton +apt +hornet +immortals +##dou +asturias +cleansing +dario +##rries +##anta +etymology +servicing +zhejiang +##venor +##nx +horned +erasmus +rayon +relocating +£10 +##bags +escalated +promenade +stubble +2010s +artisans +axial +liquids +mora +sho +yoo +##tsky +bundles +oldies +##nally +notification +bastion +##ths +sparkle +##lved +1728 +leash +pathogen +highs +##hmi +immature +880 +gonzaga +ignatius +mansions +monterrey +sweets +bryson +##loe +polled +regatta +brightest +pei +rosy +squid +hatfield +payroll +addict +meath +cornerback +heaviest +lodging +##mage +capcom +rippled +##sily +barnet +mayhem +ymca +snuggled +rousseau +##cute +blanchard +284 +fragmented +leighton +chromosomes +risking +##md +##strel +##utter +corinne +coyotes +cynical +hiroshi +yeomanry +##ractive +ebook +grading +mandela +plume +agustin +magdalene +##rkin +bea +femme +trafford +##coll +##lun +##tance +52nd +fourier +upton +##mental +camilla +gust +iihf +islamabad +longevity +##kala +feldman +netting +##rization +endeavour +foraging +mfa +orr +##open +greyish +contradiction +graz +##ruff +handicapped +marlene +tweed +oaxaca +spp +campos +miocene +pri +configured +cooks +pluto +cozy +pornographic +##entes +70th +fairness +glided +jonny +lynne +rounding +sired +##emon +##nist +remade +uncover +##mack +complied +lei +newsweek +##jured +##parts +##enting +##pg +293 +finer +guerrillas +athenian +deng +disused +stepmother +accuse +gingerly +seduction +521 +confronting +##walker +##going +gora +nostalgia +sabres +virginity +wrenched +##minated +syndication +wielding +eyre +##56 +##gnon +##igny +behaved +taxpayer +sweeps +##growth +childless +gallant +##ywood +amplified +geraldine +scrape +##ffi +babylonian +fresco +##rdan +##kney +##position +1718 +restricting +tack +fukuoka +osborn +selector +partnering +##dlow +318 +gnu +kia +tak +whitley +gables +##54 +##mania +mri +softness +immersion +##bots +##evsky +1713 +chilling +insignificant +pcs +##uis +elites +lina +purported +supplemental +teaming +##americana +##dding +##inton +proficient +rouen +##nage +##rret +niccolo +selects +##bread +fluffy +1621 +gruff +knotted +mukherjee +polgara +thrash +nicholls +secluded +smoothing +thru +corsica +loaf +whitaker +inquiries +##rrier +##kam +indochina +289 +marlins +myles +peking +##tea +extracts +pastry +superhuman +connacht +vogel +##ditional +##het +##udged +##lash +gloss +quarries +refit +teaser +##alic +##gaon +20s +materialized +sling +camped +pickering +tung +tracker +pursuant +##cide +cranes +soc +##cini +##typical +##viere +anhalt +overboard +workout +chores +fares +orphaned +stains +##logie +fenton +surpassing +joyah +triggers +##itte +grandmaster +##lass +##lists +clapping +fraudulent +ledger +nagasaki +##cor +##nosis +##tsa +eucalyptus +tun +##icio +##rney +##tara +dax +heroism +ina +wrexham +onboard +unsigned +##dates +moshe +galley +winnie +droplets +exiles +praises +watered +noodles +##aia +fein +adi +leland +multicultural +stink +bingo +comets +erskine +modernized +canned +constraint +domestically +chemotherapy +featherweight +stifled +##mum +darkly +irresistible +refreshing +hasty +isolate +##oys +kitchener +planners +##wehr +cages +yarn +implant +toulon +elects +childbirth +yue +##lind +##lone +cn +rightful +sportsman +junctions +remodeled +specifies +##rgh +291 +##oons +complimented +##urgent +lister +ot +##logic +bequeathed +cheekbones +fontana +gabby +##dial +amadeus +corrugated +maverick +resented +triangles +##hered +##usly +nazareth +tyrol +1675 +assent +poorer +sectional +aegean +##cous +296 +nylon +ghanaian +##egorical +##weig +cushions +forbid +fusiliers +obstruction +somerville +##scia +dime +earrings +elliptical +leyte +oder +polymers +timmy +atm +midtown +piloted +settles +continual +externally +mayfield +##uh +enrichment +henson +keane +persians +1733 +benji +braden +pep +324 +##efe +contenders +pepsi +valet +##isches +298 +##asse +##earing +goofy +stroll +##amen +authoritarian +occurrences +adversary +ahmedabad +tangent +toppled +dorchester +1672 +modernism +marxism +islamist +charlemagne +exponential +racks +unicode +brunette +mbc +pic +skirmish +##bund +##lad +##powered +##yst +hoisted +messina +shatter +##ctum +jedi +vantage +##music +##neil +clemens +mahmoud +corrupted +authentication +lowry +nils +##washed +omnibus +wounding +jillian +##itors +##opped +serialized +narcotics +handheld +##arm +##plicity +intersecting +stimulating +##onis +crate +fellowships +hemingway +casinos +climatic +fordham +copeland +drip +beatty +leaflets +robber +brothel +madeira +##hedral +sphinx +ultrasound +##vana +valor +forbade +leonid +villas +##aldo +duane +marquez +##cytes +disadvantaged +forearms +kawasaki +reacts +consular +lax +uncles +uphold +##hopper +concepcion +dorsey +lass +##izan +arching +passageway +1708 +researches +tia +internationals +##graphs +##opers +distinguishes +javanese +divert +##uven +plotted +##listic +##rwin +##erik +##tify +affirmative +signifies +validation +##bson +kari +felicity +georgina +zulu +##eros +##rained +##rath +overcoming +##dot +argyll +##rbin +1734 +chiba +ratification +windy +earls +parapet +##marks +hunan +pristine +astrid +punta +##gart +brodie +##kota +##oder +malaga +minerva +rouse +##phonic +bellowed +pagoda +portals +reclamation +##gur +##odies +##⁄₄ +parentheses +quoting +allergic +palette +showcases +benefactor +heartland +nonlinear +##tness +bladed +cheerfully +scans +##ety +##hone +1666 +girlfriends +pedersen +hiram +sous +##liche +##nator +1683 +##nery +##orio +##umen +bobo +primaries +smiley +##cb +unearthed +uniformly +fis +metadata +1635 +ind +##oted +recoil +##titles +##tura +##ια +406 +hilbert +jamestown +mcmillan +tulane +seychelles +##frid +antics +coli +fated +stucco +##grants +1654 +bulky +accolades +arrays +caledonian +carnage +optimism +puebla +##tative +##cave +enforcing +rotherham +seo +dunlop +aeronautics +chimed +incline +zoning +archduke +hellenistic +##oses +##sions +candi +thong +##ople +magnate +rustic +##rsk +projective +slant +##offs +danes +hollis +vocalists +##ammed +congenital +contend +gesellschaft +##ocating +##pressive +douglass +quieter +##cm +##kshi +howled +salim +spontaneously +townsville +buena +southport +##bold +kato +1638 +faerie +stiffly +##vus +##rled +297 +flawless +realising +taboo +##7th +bytes +straightening +356 +jena +##hid +##rmin +cartwright +berber +bertram +soloists +411 +noses +417 +coping +fission +hardin +inca +##cen +1717 +mobilized +vhf +##raf +biscuits +curate +##85 +##anial +331 +gaunt +neighbourhoods +1540 +##abas +blanca +bypassed +sockets +behold +coincidentally +##bane +nara +shave +splinter +terrific +##arion +##erian +commonplace +juris +redwood +waistband +boxed +caitlin +fingerprints +jennie +naturalized +##ired +balfour +craters +jody +bungalow +hugely +quilt +glitter +pigeons +undertaker +bulging +constrained +goo +##sil +##akh +assimilation +reworked +##person +persuasion +##pants +felicia +##cliff +##ulent +1732 +explodes +##dun +##inium +##zic +lyman +vulture +hog +overlook +begs +northwards +ow +spoil +##urer +fatima +favorably +accumulate +sargent +sorority +corresponded +dispersal +kochi +toned +##imi +##lita +internacional +newfound +##agger +##lynn +##rigue +booths +peanuts +##eborg +medicare +muriel +nur +##uram +crates +millennia +pajamas +worsened +##breakers +jimi +vanuatu +yawned +##udeau +carousel +##hony +hurdle +##ccus +##mounted +##pod +rv +##eche +airship +ambiguity +compulsion +recapture +##claiming +arthritis +##osomal +1667 +asserting +ngc +sniffing +dade +discontent +glendale +ported +##amina +defamation +rammed +##scent +fling +livingstone +##fleet +875 +##ppy +apocalyptic +comrade +lcd +##lowe +cessna +eine +persecuted +subsistence +demi +hoop +reliefs +710 +coptic +progressing +stemmed +perpetrators +1665 +priestess +##nio +dobson +ebony +rooster +itf +tortricidae +##bbon +##jian +cleanup +##jean +##øy +1721 +eighties +taxonomic +holiness +##hearted +##spar +antilles +showcasing +stabilized +##nb +gia +mascara +michelangelo +dawned +##uria +##vinsky +extinguished +fitz +grotesque +£100 +##fera +##loid +##mous +barges +neue +throbbed +cipher +johnnie +##a1 +##mpt +outburst +##swick +spearheaded +administrations +c1 +heartbreak +pixels +pleasantly +##enay +lombardy +plush +##nsed +bobbie +##hly +reapers +tremor +xiang +minogue +substantive +hitch +barak +##wyl +kwan +##encia +910 +obscene +elegance +indus +surfer +bribery +conserve +##hyllum +##masters +horatio +##fat +apes +rebound +psychotic +##pour +iteration +##mium +##vani +botanic +horribly +antiques +dispose +paxton +##hli +##wg +timeless +1704 +disregard +engraver +hounds +##bau +##version +looted +uno +facilitates +groans +masjid +rutland +antibody +disqualification +decatur +footballers +quake +slacks +48th +rein +scribe +stabilize +commits +exemplary +tho +##hort +##chison +pantry +traversed +##hiti +disrepair +identifiable +vibrated +baccalaureate +##nnis +csa +interviewing +##iensis +##raße +greaves +wealthiest +343 +classed +jogged +£5 +##58 +##atal +illuminating +knicks +respecting +##uno +scrubbed +##iji +##dles +kruger +moods +growls +raider +silvia +chefs +kam +vr +cree +percival +##terol +gunter +counterattack +defiant +henan +ze +##rasia +##riety +equivalence +submissions +##fra +##thor +bautista +mechanically +##heater +cornice +herbal +templar +##mering +outputs +ruining +ligand +renumbered +extravagant +mika +blockbuster +eta +insurrection +##ilia +darkening +ferocious +pianos +strife +kinship +##aer +melee +##anor +##iste +##may +##oue +decidedly +weep +##jad +##missive +##ppel +354 +puget +unease +##gnant +1629 +hammering +kassel +ob +wessex +##lga +bromwich +egan +paranoia +utilization +##atable +##idad +contradictory +provoke +##ols +##ouring +##tangled +knesset +##very +##lette +plumbing +##sden +##¹ +greensboro +occult +sniff +338 +zev +beaming +gamer +haggard +mahal +##olt +##pins +mendes +utmost +briefing +gunnery +##gut +##pher +##zh +##rok +1679 +khalifa +sonya +##boot +principals +urbana +wiring +##liffe +##minating +##rrado +dahl +nyu +skepticism +np +townspeople +ithaca +lobster +somethin +##fur +##arina +##−1 +freighter +zimmerman +biceps +contractual +##herton +amend +hurrying +subconscious +##anal +336 +meng +clermont +spawning +##eia +##lub +dignitaries +impetus +snacks +spotting +twigs +##bilis +##cz +##ouk +libertadores +nic +skylar +##aina +##firm +gustave +asean +##anum +dieter +legislatures +flirt +bromley +trolls +umar +##bbies +##tyle +blah +parc +bridgeport +crank +negligence +##nction +46th +constantin +molded +bandages +seriousness +00pm +siegel +carpets +compartments +upbeat +statehood +##dner +##edging +marko +730 +platt +##hane +paving +##iy +1738 +abbess +impatience +limousine +nbl +##talk +441 +lucille +mojo +nightfall +robbers +##nais +karel +brisk +calves +replicate +ascribed +telescopes +##olf +intimidated +##reen +ballast +specialization +##sit +aerodynamic +caliphate +rainer +visionary +##arded +epsilon +##aday +##onte +aggregation +auditory +boosted +reunification +kathmandu +loco +robyn +402 +acknowledges +appointing +humanoid +newell +redeveloped +restraints +##tained +barbarians +chopper +1609 +italiana +##lez +##lho +investigates +wrestlemania +##anies +##bib +690 +##falls +creaked +dragoons +gravely +minions +stupidity +volley +##harat +##week +musik +##eries +##uously +fungal +massimo +semantics +malvern +##ahl +##pee +discourage +embryo +imperialism +1910s +profoundly +##ddled +jiangsu +sparkled +stat +##holz +sweatshirt +tobin +##iction +sneered +##cheon +##oit +brit +causal +smyth +##neuve +diffuse +perrin +silvio +##ipes +##recht +detonated +iqbal +selma +##nism +##zumi +roasted +##riders +tay +##ados +##mament +##mut +##rud +840 +completes +nipples +cfa +flavour +hirsch +##laus +calderon +sneakers +moravian +##ksha +1622 +rq +294 +##imeters +bodo +##isance +##pre +##ronia +anatomical +excerpt +##lke +dh +kunst +##tablished +##scoe +biomass +panted +unharmed +gael +housemates +montpellier +##59 +coa +rodents +tonic +hickory +singleton +##taro +451 +1719 +aldo +breaststroke +dempsey +och +rocco +##cuit +merton +dissemination +midsummer +serials +##idi +haji +polynomials +##rdon +gs +enoch +prematurely +shutter +taunton +£3 +##grating +##inates +archangel +harassed +##asco +326 +archway +dazzling +##ecin +1736 +sumo +wat +##kovich +1086 +honneur +##ently +##nostic +##ttal +##idon +1605 +403 +1716 +blogger +rents +##gnan +hires +##ikh +##dant +howie +##rons +handler +retracted +shocks +1632 +arun +duluth +kepler +trumpeter +##lary +peeking +seasoned +trooper +##mara +laszlo +##iciencies +##rti +heterosexual +##inatory +##ssion +indira +jogging +##inga +##lism +beit +dissatisfaction +malice +##ately +nedra +peeling +##rgeon +47th +stadiums +475 +vertigo +##ains +iced +restroom +##plify +##tub +illustrating +pear +##chner +##sibility +inorganic +rappers +receipts +watery +##kura +lucinda +##oulos +reintroduced +##8th +##tched +gracefully +saxons +nutritional +wastewater +rained +favourites +bedrock +fisted +hallways +likeness +upscale +##lateral +1580 +blinds +prequel +##pps +##tama +deter +humiliating +restraining +tn +vents +1659 +laundering +recess +rosary +tractors +coulter +federer +##ifiers +##plin +persistence +##quitable +geschichte +pendulum +quakers +##beam +bassett +pictorial +buffet +koln +##sitor +drills +reciprocal +shooters +##57 +##cton +##tees +converge +pip +dmitri +donnelly +yamamoto +aqua +azores +demographics +hypnotic +spitfire +suspend +wryly +roderick +##rran +sebastien +##asurable +mavericks +##fles +##200 +himalayan +prodigy +##iance +transvaal +demonstrators +handcuffs +dodged +mcnamara +sublime +1726 +crazed +##efined +##till +ivo +pondered +reconciled +shrill +sava +##duk +bal +cad +heresy +jaipur +goran +##nished +341 +lux +shelly +whitehall +##hre +israelis +peacekeeping +##wled +1703 +demetrius +ousted +##arians +##zos +beale +anwar +backstroke +raged +shrinking +cremated +##yck +benign +towing +wadi +darmstadt +landfill +parana +soothe +colleen +sidewalks +mayfair +tumble +hepatitis +ferrer +superstructure +##gingly +##urse +##wee +anthropological +translators +##mies +closeness +hooves +##pw +mondays +##roll +##vita +landscaping +##urized +purification +sock +thorns +thwarted +jalan +tiberius +##taka +saline +##rito +confidently +khyber +sculptors +##ij +brahms +hammersmith +inspectors +battista +fivb +fragmentation +hackney +##uls +arresting +exercising +antoinette +bedfordshire +##zily +dyed +##hema +1656 +racetrack +variability +##tique +1655 +austrians +deteriorating +madman +theorists +aix +lehman +weathered +1731 +decreed +eruptions +1729 +flaw +quinlan +sorbonne +flutes +nunez +1711 +adored +downwards +fable +rasped +1712 +moritz +mouthful +renegade +shivers +stunts +dysfunction +restrain +translit +327 +pancakes +##avio +##cision +##tray +351 +vial +##lden +bain +##maid +##oxide +chihuahua +malacca +vimes +##rba +##rnier +1664 +donnie +plaques +##ually +337 +bangs +floppy +huntsville +loretta +nikolay +##otte +eater +handgun +ubiquitous +##hett +eras +zodiac +1634 +##omorphic +1820s +##zog +cochran +##bula +##lithic +warring +##rada +dalai +excused +blazers +mcconnell +reeling +bot +este +##abi +geese +hoax +taxon +##bla +guitarists +##icon +condemning +hunts +inversion +moffat +taekwondo +##lvis +1624 +stammered +##rest +##rzy +sousa +fundraiser +marylebone +navigable +uptown +cabbage +daniela +salman +shitty +whimper +##kian +##utive +programmers +protections +rm +##rmi +##rued +forceful +##enes +fuss +##tao +##wash +brat +oppressive +reykjavik +spartak +ticking +##inkles +##kiewicz +adolph +horst +maui +protege +straighten +cpc +landau +concourse +clements +resultant +##ando +imaginative +joo +reactivated +##rem +##ffled +##uising +consultative +##guide +flop +kaitlyn +mergers +parenting +somber +##vron +supervise +vidhan +##imum +courtship +exemplified +harmonies +medallist +refining +##rrow +##ка +amara +##hum +780 +goalscorer +sited +overshadowed +rohan +displeasure +secretive +multiplied +osman +##orth +engravings +padre +##kali +##veda +miniatures +mis +##yala +clap +pali +rook +##cana +1692 +57th +antennae +astro +oskar +1628 +bulldog +crotch +hackett +yucatan +##sure +amplifiers +brno +ferrara +migrating +##gree +thanking +turing +##eza +mccann +ting +andersson +onslaught +gaines +ganga +incense +standardization +##mation +sentai +scuba +stuffing +turquoise +waivers +alloys +##vitt +regaining +vaults +##clops +##gizing +digger +furry +memorabilia +probing +##iad +payton +rec +deutschland +filippo +opaque +seamen +zenith +afrikaans +##filtration +disciplined +inspirational +##merie +banco +confuse +grafton +tod +##dgets +championed +simi +anomaly +biplane +##ceptive +electrode +##para +1697 +cleavage +crossbow +swirl +informant +##lars +##osta +afi +bonfire +spec +##oux +lakeside +slump +##culus +##lais +##qvist +##rrigan +1016 +facades +borg +inwardly +cervical +xl +pointedly +050 +stabilization +##odon +chests +1699 +hacked +ctv +orthogonal +suzy +##lastic +gaulle +jacobite +rearview +##cam +##erted +ashby +##drik +##igate +##mise +##zbek +affectionately +canine +disperse +latham +##istles +##ivar +spielberg +##orin +##idium +ezekiel +cid +##sg +durga +middletown +##cina +customized +frontiers +harden +##etano +##zzy +1604 +bolsheviks +##66 +coloration +yoko +##bedo +briefs +slabs +debra +liquidation +plumage +##oin +blossoms +dementia +subsidy +1611 +proctor +relational +jerseys +parochial +ter +##ici +esa +peshawar +cavalier +loren +cpi +idiots +shamrock +1646 +dutton +malabar +mustache +##endez +##ocytes +referencing +terminates +marche +yarmouth +##sop +acton +mated +seton +subtly +baptised +beige +extremes +jolted +kristina +telecast +##actic +safeguard +waldo +##baldi +##bular +endeavors +sloppy +subterranean +##ensburg +##itung +delicately +pigment +tq +##scu +1626 +##ound +collisions +coveted +herds +##personal +##meister +##nberger +chopra +##ricting +abnormalities +defective +galician +lucie +##dilly +alligator +likened +##genase +burundi +clears +complexion +derelict +deafening +diablo +fingered +champaign +dogg +enlist +isotope +labeling +mrna +##erre +brilliance +marvelous +##ayo +1652 +crawley +ether +footed +dwellers +deserts +hamish +rubs +warlock +skimmed +##lizer +870 +buick +embark +heraldic +irregularities +##ajan +kiara +##kulam +##ieg +antigen +kowalski +##lge +oakley +visitation +##mbit +vt +##suit +1570 +murderers +##miento +##rites +chimneys +##sling +condemn +custer +exchequer +havre +##ghi +fluctuations +##rations +dfb +hendricks +vaccines +##tarian +nietzsche +biking +juicy +##duced +brooding +scrolling +selangor +##ragan +352 +annum +boomed +seminole +sugarcane +##dna +departmental +dismissing +innsbruck +arteries +ashok +batavia +daze +kun +overtook +##rga +##tlan +beheaded +gaddafi +holm +electronically +faulty +galilee +fractures +kobayashi +##lized +gunmen +magma +aramaic +mala +eastenders +inference +messengers +bf +##qu +407 +bathrooms +##vere +1658 +flashbacks +ideally +misunderstood +##jali +##weather +mendez +##grounds +505 +uncanny +##iii +1709 +friendships +##nbc +sacrament +accommodated +reiterated +logistical +pebbles +thumped +##escence +administering +decrees +drafts +##flight +##cased +##tula +futuristic +picket +intimidation +winthrop +##fahan +interfered +339 +afar +francoise +morally +uta +cochin +croft +dwarfs +##bruck +##dents +##nami +biker +##hner +##meral +nano +##isen +##ometric +##pres +##ан +brightened +meek +parcels +securely +gunners +##jhl +##zko +agile +hysteria +##lten +##rcus +bukit +champs +chevy +cuckoo +leith +sadler +theologians +welded +##section +1663 +jj +plurality +xander +##rooms +##formed +shredded +temps +intimately +pau +tormented +##lok +##stellar +1618 +charred +ems +essen +##mmel +alarms +spraying +ascot +blooms +twinkle +##abia +##apes +internment +obsidian +##chaft +snoop +##dav +##ooping +malibu +##tension +quiver +##itia +hays +mcintosh +travers +walsall +##ffie +1623 +beverley +schwarz +plunging +structurally +m3 +rosenthal +vikram +##tsk +770 +ghz +##onda +##tiv +chalmers +groningen +pew +reckon +unicef +##rvis +55th +##gni +1651 +sulawesi +avila +cai +metaphysical +screwing +turbulence +##mberg +augusto +samba +56th +baffled +momentary +toxin +##urian +##wani +aachen +condoms +dali +steppe +##3d +##app +##oed +##year +adolescence +dauphin +electrically +inaccessible +microscopy +nikita +##ega +atv +##cel +##enter +##oles +##oteric +##ы +accountants +punishments +wrongly +bribes +adventurous +clinch +flinders +southland +##hem +##kata +gough +##ciency +lads +soared +##ה +undergoes +deformation +outlawed +rubbish +##arus +##mussen +##nidae +##rzburg +arcs +##ingdon +##tituted +1695 +wheelbase +wheeling +bombardier +campground +zebra +##lices +##oj +##bain +lullaby +##ecure +donetsk +wylie +grenada +##arding +##ης +squinting +eireann +opposes +##andra +maximal +runes +##broken +##cuting +##iface +##ror +##rosis +additive +britney +adultery +triggering +##drome +detrimental +aarhus +containment +jc +swapped +vichy +##ioms +madly +##oric +##rag +brant +##ckey +##trix +1560 +1612 +broughton +rustling +##stems +##uder +asbestos +mentoring +##nivorous +finley +leaps +##isan +apical +pry +slits +substitutes +##dict +intuitive +fantasia +insistent +unreasonable +##igen +##vna +domed +hannover +margot +ponder +##zziness +impromptu +jian +lc +rampage +stemming +##eft +andrey +gerais +whichever +amnesia +appropriated +anzac +clicks +modifying +ultimatum +cambrian +maids +verve +yellowstone +##mbs +conservatoire +##scribe +adherence +dinners +spectra +imperfect +mysteriously +sidekick +tatar +tuba +##aks +##ifolia +distrust +##athan +##zle +c2 +ronin +zac +##pse +celaena +instrumentalist +scents +skopje +##mbling +comical +compensated +vidal +condor +intersect +jingle +wavelengths +##urrent +mcqueen +##izzly +carp +weasel +422 +kanye +militias +postdoctoral +eugen +gunslinger +##ɛ +faux +hospice +##for +appalled +derivation +dwarves +##elis +dilapidated +##folk +astoria +philology +##lwyn +##otho +##saka +inducing +philanthropy +##bf +##itative +geek +markedly +sql +##yce +bessie +indices +rn +##flict +495 +frowns +resolving +weightlifting +tugs +cleric +contentious +1653 +mania +rms +##miya +##reate +##ruck +##tucket +bien +eels +marek +##ayton +##cence +discreet +unofficially +##ife +leaks +##bber +1705 +332 +dung +compressor +hillsborough +pandit +shillings +distal +##skin +381 +##tat +##you +nosed +##nir +mangrove +undeveloped +##idia +textures +##inho +##500 +##rise +ae +irritating +nay +amazingly +bancroft +apologetic +compassionate +kata +symphonies +##lovic +airspace +##lch +930 +gifford +precautions +fulfillment +sevilla +vulgar +martinique +##urities +looting +piccolo +tidy +##dermott +quadrant +armchair +incomes +mathematicians +stampede +nilsson +##inking +##scan +foo +quarterfinal +##ostal +shang +shouldered +squirrels +##owe +344 +vinegar +##bner +##rchy +##systems +delaying +##trics +ars +dwyer +rhapsody +sponsoring +##gration +bipolar +cinder +starters +##olio +##urst +421 +signage +##nty +aground +figurative +mons +acquaintances +duets +erroneously +soyuz +elliptic +recreated +##cultural +##quette +##ssed +##tma +##zcz +moderator +scares +##itaire +##stones +##udence +juniper +sighting +##just +##nsen +britten +calabria +ry +bop +cramer +forsyth +stillness +##л +airmen +gathers +unfit +##umber +##upt +taunting +##rip +seeker +streamlined +##bution +holster +schumann +tread +vox +##gano +##onzo +strive +dil +reforming +covent +newbury +predicting +##orro +decorate +tre +##puted +andover +ie +asahi +dept +dunkirk +gills +##tori +buren +huskies +##stis +##stov +abstracts +bets +loosen +##opa +1682 +yearning +##glio +##sir +berman +effortlessly +enamel +napoli +persist +##peration +##uez +attache +elisa +b1 +invitations +##kic +accelerating +reindeer +boardwalk +clutches +nelly +polka +starbucks +##kei +adamant +huey +lough +unbroken +adventurer +embroidery +inspecting +stanza +##ducted +naia +taluka +##pone +##roids +chases +deprivation +florian +##jing +##ppet +earthly +##lib +##ssee +colossal +foreigner +vet +freaks +patrice +rosewood +triassic +upstate +##pkins +dominates +ata +chants +ks +vo +##400 +##bley +##raya +##rmed +555 +agra +infiltrate +##ailing +##ilation +##tzer +##uppe +##werk +binoculars +enthusiast +fujian +squeak +##avs +abolitionist +almeida +boredom +hampstead +marsden +rations +##ands +inflated +334 +bonuses +rosalie +patna +##rco +329 +detachments +penitentiary +54th +flourishing +woolf +##dion +##etched +papyrus +##lster +##nsor +##toy +bobbed +dismounted +endelle +inhuman +motorola +tbs +wince +wreath +##ticus +hideout +inspections +sanjay +disgrace +infused +pudding +stalks +##urbed +arsenic +leases +##hyl +##rrard +collarbone +##waite +##wil +dowry +##bant +##edance +genealogical +nitrate +salamanca +scandals +thyroid +necessitated +##! +##" +### +##$ +##% +##& +##' +##( +##) +##* +##+ +##, +##- +##. +##/ +##: +##; +##< +##= +##> +##? +##@ +##[ +##\ +##] +##^ +##_ +##` +##{ +##| +##} +##~ +##¡ +##¢ +##£ +##¤ +##¥ +##¦ +##§ +##¨ +##© +##ª +##« +##¬ +##® +##± +##´ +##µ +##¶ +##· +##º +##» +##¼ +##¾ +##¿ +##æ +##ð +##÷ +##þ +##đ +##ħ +##ŋ +##œ +##ƒ +##ɐ +##ɑ +##ɒ +##ɔ +##ɕ +##ə +##ɡ +##ɣ +##ɨ +##ɪ +##ɫ +##ɬ +##ɯ +##ɲ +##ɴ +##ɹ +##ɾ +##ʀ +##ʁ +##ʂ +##ʃ +##ʉ +##ʊ +##ʋ +##ʌ +##ʎ +##ʐ +##ʑ +##ʒ +##ʔ +##ʰ +##ʲ +##ʳ +##ʷ +##ʸ +##ʻ +##ʼ +##ʾ +##ʿ +##ˈ +##ˡ +##ˢ +##ˣ +##ˤ +##β +##γ +##δ +##ε +##ζ +##θ +##κ +##λ +##μ +##ξ +##ο +##π +##ρ +##σ +##τ +##υ +##φ +##χ +##ψ +##ω +##б +##г +##д +##ж +##з +##м +##п +##с +##у +##ф +##х +##ц +##ч +##ш +##щ +##ъ +##э +##ю +##ђ +##є +##і +##ј +##љ +##њ +##ћ +##ӏ +##ա +##բ +##գ +##դ +##ե +##թ +##ի +##լ +##կ +##հ +##մ +##յ +##ն +##ո +##պ +##ս +##վ +##տ +##ր +##ւ +##ք +##־ +##א +##ב +##ג +##ד +##ו +##ז +##ח +##ט +##י +##ך +##כ +##ל +##ם +##מ +##ן +##נ +##ס +##ע +##ף +##פ +##ץ +##צ +##ק +##ר +##ש +##ת +##، +##ء +##ب +##ت +##ث +##ج +##ح +##خ +##ذ +##ز +##س +##ش +##ص +##ض +##ط +##ظ +##ع +##غ +##ـ +##ف +##ق +##ك +##و +##ى +##ٹ +##پ +##چ +##ک +##گ +##ں +##ھ +##ہ +##ے +##अ +##आ +##उ +##ए +##क +##ख +##ग +##च +##ज +##ट +##ड +##ण +##त +##थ +##द +##ध +##न +##प +##ब +##भ +##म +##य +##र +##ल +##व +##श +##ष +##स +##ह +##ा +##ि +##ी +##ो +##। +##॥ +##ং +##অ +##আ +##ই +##উ +##এ +##ও +##ক +##খ +##গ +##চ +##ছ +##জ +##ট +##ড +##ণ +##ত +##থ +##দ +##ধ +##ন +##প +##ব +##ভ +##ম +##য +##র +##ল +##শ +##ষ +##স +##হ +##া +##ি +##ী +##ে +##க +##ச +##ட +##த +##ந +##ன +##ப +##ம +##ய +##ர +##ல +##ள +##வ +##ா +##ி +##ு +##ே +##ை +##ನ +##ರ +##ಾ +##ක +##ය +##ර +##ල +##ව +##ා +##ก +##ง +##ต +##ท +##น +##พ +##ม +##ย +##ร +##ล +##ว +##ส +##อ +##า +##เ +##་ +##། +##ག +##ང +##ད +##ན +##པ +##བ +##མ +##འ +##ར +##ལ +##ས +##မ +##ა +##ბ +##გ +##დ +##ე +##ვ +##თ +##ი +##კ +##ლ +##მ +##ნ +##ო +##რ +##ს +##ტ +##უ +##ᄀ +##ᄂ +##ᄃ +##ᄅ +##ᄆ +##ᄇ +##ᄉ +##ᄊ +##ᄋ +##ᄌ +##ᄎ +##ᄏ +##ᄐ +##ᄑ +##ᄒ +##ᅡ +##ᅢ +##ᅥ +##ᅦ +##ᅧ +##ᅩ +##ᅪ +##ᅭ +##ᅮ +##ᅯ +##ᅲ +##ᅳ +##ᅴ +##ᅵ +##ᆨ +##ᆫ +##ᆯ +##ᆷ +##ᆸ +##ᆼ +##ᴬ +##ᴮ +##ᴰ +##ᴵ +##ᴺ +##ᵀ +##ᵃ +##ᵇ +##ᵈ +##ᵉ +##ᵍ +##ᵏ +##ᵐ +##ᵒ +##ᵖ +##ᵗ +##ᵘ +##ᵣ +##ᵤ +##ᵥ +##ᶜ +##ᶠ +##‐ +##‑ +##‒ +##– +##— +##― +##‖ +##‘ +##’ +##‚ +##“ +##” +##„ +##† +##‡ +##• +##… +##‰ +##′ +##″ +##› +##‿ +##⁄ +##⁰ +##ⁱ +##⁴ +##⁵ +##⁶ +##⁷ +##⁸ +##⁹ +##⁻ +##ⁿ +##₅ +##₆ +##₇ +##₈ +##₉ +##₊ +##₍ +##₎ +##ₐ +##ₑ +##ₒ +##ₓ +##ₕ +##ₖ +##ₗ +##ₘ +##ₚ +##ₛ +##ₜ +##₤ +##₩ +##€ +##₱ +##₹ +##ℓ +##№ +##ℝ +##™ +##⅓ +##⅔ +##← +##↑ +##→ +##↓ +##↔ +##↦ +##⇄ +##⇌ +##⇒ +##∂ +##∅ +##∆ +##∇ +##∈ +##∗ +##∘ +##√ +##∞ +##∧ +##∨ +##∩ +##∪ +##≈ +##≡ +##≤ +##≥ +##⊂ +##⊆ +##⊕ +##⊗ +##⋅ +##─ +##│ +##■ +##▪ +##● +##★ +##☆ +##☉ +##♠ +##♣ +##♥ +##♦ +##♯ +##⟨ +##⟩ +##ⱼ +##⺩ +##⺼ +##⽥ +##、 +##。 +##〈 +##〉 +##《 +##》 +##「 +##」 +##『 +##』 +##〜 +##あ +##い +##う +##え +##お +##か +##き +##く +##け +##こ +##さ +##し +##す +##せ +##そ +##た +##ち +##っ +##つ +##て +##と +##な +##に +##ぬ +##ね +##の +##は +##ひ +##ふ +##へ +##ほ +##ま +##み +##む +##め +##も +##や +##ゆ +##よ +##ら +##り +##る +##れ +##ろ +##を +##ん +##ァ +##ア +##ィ +##イ +##ウ +##ェ +##エ +##オ +##カ +##キ +##ク +##ケ +##コ +##サ +##シ +##ス +##セ +##タ +##チ +##ッ +##ツ +##テ +##ト +##ナ +##ニ +##ノ +##ハ +##ヒ +##フ +##ヘ +##ホ +##マ +##ミ +##ム +##メ +##モ +##ャ +##ュ +##ョ +##ラ +##リ +##ル +##レ +##ロ +##ワ +##ン +##・ +##ー +##一 +##三 +##上 +##下 +##不 +##世 +##中 +##主 +##久 +##之 +##也 +##事 +##二 +##五 +##井 +##京 +##人 +##亻 +##仁 +##介 +##代 +##仮 +##伊 +##会 +##佐 +##侍 +##保 +##信 +##健 +##元 +##光 +##八 +##公 +##内 +##出 +##分 +##前 +##劉 +##力 +##加 +##勝 +##北 +##区 +##十 +##千 +##南 +##博 +##原 +##口 +##古 +##史 +##司 +##合 +##吉 +##同 +##名 +##和 +##囗 +##四 +##国 +##國 +##土 +##地 +##坂 +##城 +##堂 +##場 +##士 +##夏 +##外 +##大 +##天 +##太 +##夫 +##奈 +##女 +##子 +##学 +##宀 +##宇 +##安 +##宗 +##定 +##宣 +##宮 +##家 +##宿 +##寺 +##將 +##小 +##尚 +##山 +##岡 +##島 +##崎 +##川 +##州 +##巿 +##帝 +##平 +##年 +##幸 +##广 +##弘 +##張 +##彳 +##後 +##御 +##德 +##心 +##忄 +##志 +##忠 +##愛 +##成 +##我 +##戦 +##戸 +##手 +##扌 +##政 +##文 +##新 +##方 +##日 +##明 +##星 +##春 +##昭 +##智 +##曲 +##書 +##月 +##有 +##朝 +##木 +##本 +##李 +##村 +##東 +##松 +##林 +##森 +##楊 +##樹 +##橋 +##歌 +##止 +##正 +##武 +##比 +##氏 +##民 +##水 +##氵 +##氷 +##永 +##江 +##沢 +##河 +##治 +##法 +##海 +##清 +##漢 +##瀬 +##火 +##版 +##犬 +##王 +##生 +##田 +##男 +##疒 +##発 +##白 +##的 +##皇 +##目 +##相 +##省 +##真 +##石 +##示 +##社 +##神 +##福 +##禾 +##秀 +##秋 +##空 +##立 +##章 +##竹 +##糹 +##美 +##義 +##耳 +##良 +##艹 +##花 +##英 +##華 +##葉 +##藤 +##行 +##街 +##西 +##見 +##訁 +##語 +##谷 +##貝 +##貴 +##車 +##軍 +##辶 +##道 +##郎 +##郡 +##部 +##都 +##里 +##野 +##金 +##鈴 +##镇 +##長 +##門 +##間 +##阝 +##阿 +##陳 +##陽 +##雄 +##青 +##面 +##風 +##食 +##香 +##馬 +##高 +##龍 +##龸 +##fi +##fl +##! +##( +##) +##, +##- +##. +##/ +##: +##? +##~ diff --git a/flow-Agent/optimize.py b/flow-Agent/optimize.py index f8c4045..630c2e0 100644 --- a/flow-Agent/optimize.py +++ b/flow-Agent/optimize.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 - import json import os import sys @@ -9,11 +8,27 @@ import anthropic import csv import random - +from rag.util import answerWithRAG +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from sentence_transformers import SentenceTransformer +import torch +from pathlib import Path +from openai import OpenAI from inspectfuncs import * from modelfuncs import * from agglomfuncs import * +print("Python executable:", sys.executable) +print("sys.path:", sys.path[:3]) +print("Current working dir:", os.getcwd()) + +for pkg in ["anthropic", "sentence_transformers", "torch", "openai"]: + try: + __import__(pkg) + print(f"Imported {pkg}") + except ImportError as e: + print(f"Failed to import {pkg}: {e}") + def process_log_file(log_path: str) -> Dict[str, Any]: """Process a single log file to extract relevant metrics""" run_data = { @@ -25,6 +40,7 @@ def process_log_file(log_path: str) -> Dict[str, Any]: with open(log_path, 'r') as f: content = f.read() + print(f"File size: {len(content)} characters") # Extract timing information timing_metrics = extract_timing_metrics(content) @@ -37,8 +53,13 @@ def process_log_file(log_path: str) -> Dict[str, Any]: # Extract any errors errors = extract_errors(content) run_data['errors'].extend(errors) - - # Determine success based on completion markers and errors + # === Inject a simulated error for testing RAG debugging === + # if "run3" in log_path: # You can change it to any run,eg. run1 or run2 + # fake_error = "[ERROR] TEST_SIM: Simulated routing congestion failure" + # print(f"[DEBUG] Injected simulated error in {log_path}: {fake_error}") + # run_data['errors'].append(fake_error) + # run_data['success'] = False + run_data['success'] = is_run_successful(content, errors) return run_data @@ -53,17 +74,20 @@ def extract_timing_metrics(log_content: str) -> Dict[str, float]: metrics['worst_slack'] = float(slack_match.group(1)) # Extract CTS worst slack - cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) if cts_slack_match: metrics['cts_ws'] = float(cts_slack_match.group(1)) # Extract clock period - period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) if period_match: metrics['clock_period'] = float(period_match.group(1)) # Extract TNS - tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) if tns_match: metrics['tns'] = float(tns_match.group(1)) @@ -79,7 +103,8 @@ def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: metrics['total_wirelength'] = float(wl_match.group(1)) # Extract estimated wirelength after CTS - cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) if cts_wl_match: metrics['cts_wirelength'] = float(cts_wl_match.group(1)) @@ -103,19 +128,200 @@ def extract_errors(log_content: str) -> List[str]: return errors -def is_run_successful(log_content: str, errors: List[str]) -> bool: +def is_run_successful(log_content: str, errors: List[str], filename: str = "") -> bool: """Determine if a run was successful based on log content and errors""" if errors: + # If any real error lines were found, this file is a failure indicator return False # Look for completion markers completion_markers = [ 'Flow complete', 'Finished successfully' + 'Writing out GDS/OAS', + '6_report' ] return any(marker in log_content for marker in completion_markers) + +class ReActFramework: + """ReAct framework implementation""" + + def __init__(self, client, model_name="DeepSeek-V3"): + self.client = client + self.model_name = model_name + self.conversation_history = [] + + def add_to_history(self, role: str, content: str): + """add conversation history""" + self.conversation_history.append({"role": role, "content": content}) + + def clear_history(self): + """clear conversation history""" + self.conversation_history = [] + + def extract_thought_action(self, response: str) -> Tuple[str, str, str]: + """ + Extract Thought, Action, and Action Input from LLM responses + Format: Thought:... Action:... Action Input: ... + """ + thought = "" + action = "" + action_input = "" + + # Extract Thought + thought_match = re.search(r'Thought:\s*(.*?)(?=\nAction:|$)', response, re.DOTALL) + if thought_match: + thought = thought_match.group(1).strip() + + # Extract Action + action_match = re.search(r'Action:\s*(\w+)', response) + if action_match: + action = action_match.group(1).strip() + + # Extract Action Input + action_input_match = re.search(r'Action Input:\s*(.*?)(?=\nObservation:|$)', response, re.DOTALL) + if action_input_match: + action_input = action_input_match.group(1).strip() + # Try to parse JSON + try: + if action_input.startswith('{') or action_input.startswith('['): + action_input = json.loads(action_input) + except: + pass # Maintain the string format + + if "Final Answer:" in response and ("Action:" in response or "Observation:" in response): + + response = response.split("Final Answer:")[0] + print("Removed premature Final Answer from response") + + return thought, action, action_input + + def execute_action(self, action: str, action_input: Any, available_tools: Dict) -> str: + """Execute tool call and return observation results""" + if action in available_tools: + try: + result = available_tools[action](action_input) + return f"Action executed successfully. Result: {result}" + except Exception as e: + return f"Action execution failed: {str(e)}" + else: + return f"Unknown action: {action}. Available actions: {list(available_tools.keys())}" + + def run_react_cycle(self, + initial_prompt: str, + available_tools: Dict, + max_steps: int = 5, + temperature: float = 0.1) -> Dict[str, Any]: + """ + Run ReAct loop + + Args: + initial_prompt: Initial prompt + available_tools: Available tool function dictionary + max_steps: Maximum reasoning steps + temperature: temperature parameter + + Returns: + a dictionary containing the final result and the reasoning history + """ + self.clear_history() + self.add_to_history("user", initial_prompt) + + history = [] + final_answer = None + completed_steps = 0 + + for step in range(max_steps): + print(f"\n=== ReAct Step {step + 1}/{max_steps} ===") + completed_steps = step + 1 + + # Call LLM to obtain response + try: + response = self.client.chat.completions.create( + model=self.model_name, + messages=self.conversation_history, + temperature=temperature, + max_tokens=1024 + ) + + llm_response = response.choices[0].message.content + print(f"LLM Response: {llm_response}") + except Exception as e: + print(f"Error calling LLM: {e}") + llm_response = f"Error in LLM call: {e}" + + # Extract Thought, Action, Action Input + thought, action, action_input = self.extract_thought_action(llm_response) + + step_data = { + "step": step + 1, + "thought": thought, + "action": action, + "action_input": action_input, + "llm_response": llm_response + } + + # Check if it is the final answer + final_answer_detected = False + if "Final Answer:" in llm_response: + final_answer_match = re.search(r'Final Answer:\s*(.*?)$', llm_response, re.DOTALL) + if final_answer_match: + final_answer = final_answer_match.group(1).strip() + step_data["final_answer"] = final_answer + final_answer_detected = True + print(f"Final answer detected at step {step + 1}") + + observation = "" + # Execute actions and obtain observation results + if action and not final_answer_detected: + observation = self.execute_action(action, action_input, available_tools) + step_data["observation"] = observation + + # Update conversation history + self.add_to_history("assistant", llm_response) + self.add_to_history("user", f"Observation: {observation}") + + print(f"Thought: {thought}") + print(f"Action: {action}") + print(f"Action Input: {action_input}") + print(f"Observation: {observation}") + else: + if not final_answer_detected: + # If there is no clear action, it may be during the reasoning process + self.add_to_history("assistant", llm_response) + step_data["observation"] = "No action taken - continuing reasoning" + observation = "No action taken" + else: + # If it is the final answer, no further action is required + step_data["observation"] = "Final answer provided - cycle complete" + observation = "Final answer provided" + + history.append(step_data) + + if final_answer_detected: + print(f" ReAct cycle completed at step {step + 1} with final answer") + break + + # Check if it should end early + if step >= max_steps - 1: + final_answer = f"Reached maximum steps ({max_steps}) without final answer" + print(f" Reached maximum steps without final answer") + break + + if final_answer is None: + final_answer = "No final answer produced" + + return { + "final_answer": final_answer, + "reasoning_history": history, + "success": final_answer is not None and "Reached maximum steps" not in final_answer and "No final answer" not in final_answer, + "completed_steps": completed_steps, + "max_steps": max_steps + } + + class OptimizationWorkflow: def __init__(self, platform: str, design: str, objective: str): self.platform = platform @@ -196,6 +402,974 @@ def __init__(self, platform: str, design: str, objective: str): # Load initial parameters and SDC context self.initial_params = self._load_initial_params() self.sdc_context = self._load_sdc_context() + + emb_np, docs, docsDict = load_embeddings_and_docs() + self.rag_embeddings = torch.tensor(emb_np).cpu() + self.rag_docs = docs + self.rag_docsDict = docsDict + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + model_path = model_path.resolve() + self.rag_model = SentenceTransformer(str(model_path)) + + self.react_framework = ReActFramework( + client=OpenAI( + base_url="https://ai.gitee.com/v1", + api_key= #PUT YOUR KEY HERE, + ), + model_name="DeepSeek-V3" + ) + + def _create_react_tools(self, stage: str, data: Dict[str, Any]) -> Dict: + """Create available utility functions for different stages""" + + base_tools = { + "analyze_data_distribution": lambda x: self._call_existing_distribution_analysis(data), + "analyze_data_structure": lambda x: self._call_existing_structure_analysis(data), + "evaluate_parameter_ranges": lambda x: self._evaluate_parameter_ranges(data), + "check_constraints": lambda x: self._check_constraints_compliance(data), + "suggest_improvements": lambda x: self._suggest_improvements(stage, data), + } + + if stage == 'inspect': + inspection_tools = { + "configure_inspection": lambda config: self._configure_inspection_with_existing(config, data), + "analyze_correlations": lambda params: self._analyze_correlations_with_existing(params, data), + "cluster_analysis": lambda config: self._cluster_analysis_with_existing(config, data), + "manifold_analysis": lambda config: self._manifold_analysis_with_existing(config, data), + "local_structure_analysis": lambda config: self._local_structure_analysis_with_existing(config, data), + } + base_tools.update(inspection_tools) + + elif stage == 'model': + modeling_tools = { + "configure_model": lambda config: self._configure_model_with_existing(config, data), + "evaluate_surrogate": lambda params: self._evaluate_surrogate_with_existing(params, data), + "select_acquisition": lambda method: self._select_acquisition_with_existing(method, data), + "create_surrogate_model": lambda config: self._create_surrogate_model_with_existing(config, data), + "evaluate_timing_model": lambda x: self._evaluate_timing_model_with_existing(data), + "evaluate_wirelength_model": lambda x: self._evaluate_wirelength_model_with_existing(data), + "get_model_recommendations": lambda x: self._get_model_recommendations_from_existing(data), + } + base_tools.update(modeling_tools) + + elif stage == 'agglomerate': + selection_tools = { + "configure_selection": lambda config: self._configure_selection_with_existing(config, data), + "generate_parameters": lambda count: self._generate_parameters_with_existing(count, data), + "validate_parameters": lambda params: self._validate_parameters_tool(params), + "latin_hypercube_sampling": lambda config: self._latin_hypercube_sampling_with_existing(config, data), + "create_quality_scores": lambda config: self._create_quality_scores_with_existing(config, data), + "select_points": lambda config: self._select_points_with_existing(config, data), + "compare_selection_methods": lambda config: self._compare_selection_methods_with_existing(config, data), + "kmeans_selection": lambda config: self._kmeans_selection_with_existing(config, data), + "hybrid_selection": lambda config: self._hybrid_selection_with_existing(config, data), + "entropy_selection": lambda config: self._entropy_selection_with_existing(config, data), + "graph_selection": lambda config: self._graph_selection_with_existing(config, data), + } + base_tools.update(selection_tools) + + return base_tools + + + def _call_existing_distribution_analysis(self, data: Dict) -> str: + """Call existing data distribution analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_distribution(X, Y) + return self._format_analysis_result("Data Distribution Analysis", result) + else: + return "Insufficient data for distribution analysis" + + except Exception as e: + return f"Error in distribution analysis: {str(e)}" + + def _call_existing_structure_analysis(self, data: Dict) -> str: + """Call existing data structure analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Use default configuration or retrieve configuration from data + config = { + "n_clusters": 5, + "correlation_threshold": 0.5, + "n_neighbors": 20, + "perplexity": 30 + } + + result = inspect_data_structure(X, Y, config) + return self._format_analysis_result("Data Structure Analysis", result) + else: + return "Insufficient data for structure analysis" + + except Exception as e: + return f"Error in structure analysis: {str(e)}" + + def _evaluate_parameter_ranges(self, data: Dict) -> str: + """Evaluation Parameter Range Tool - Implementation""" + constraints_info = "Parameter Constraints Evaluation:\n" + + # Analyze the current usage of parameters + param_usage = {} + for run in data.get('log_data', {}).get('runs', []): + if run.get('parameters'): + for param, value in run['parameters'].items(): + if param not in param_usage: + param_usage[param] = [] + param_usage[param].append(float(value)) + + for param, info in self.param_constraints.items(): + min_val, max_val = info['range'] + param_type = info['type'] + + constraints_info += f"\n- {param} ({param_type}): range [{min_val}, {max_val}]" + + if param in param_usage: + values = param_usage[param] + used_min = min(values) + used_max = max(values) + constraints_info += f"\n Currently used: [{used_min:.2f}, {used_max:.2f}]" + + # Check if the parameter space has been fully explored + range_used = (used_max - used_min) / (max_val - min_val) + if range_used < 0.5: + constraints_info += f" (Only {range_used*100:.1f}% of range explored)" + + return constraints_info + + def _check_constraints_compliance(self, data: Dict) -> str: + """Check Constraint Compliance Tool - Implementation""" + violations = [] + constraint_checks = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and run.get('parameters'): + params = run['parameters'] + + # Check the basic scope constraints + for param, value in params.items(): + if param in self.param_constraints: + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + if value < min_val or value > max_val: + violations.append(f"{param}={value} not in [{min_val}, {max_val}]") + + # Check domain constraints + if not self._validate_domain_constraints(params): + violations.append(f"Domain constraints violated for run with params: {params}") + + if violations: + constraint_checks.append(f"Constraint violations found in {len(violations)} cases:") + constraint_checks.extend(violations[:5]) # Only display the first 5 + else: + constraint_checks.append("All parameters comply with constraints") + + # Check the effectiveness of parameter combinations + successful_count = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('success') and run.get('parameters')) + total_with_params = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('parameters')) + + if total_with_params > 0: + success_rate = successful_count / total_with_params * 100 + constraint_checks.append(f"\nParameter success rate: {success_rate:.1f}%") + + return "\n".join(constraint_checks) + + def _suggest_improvements(self, stage: str, data: Dict) -> str: + """Provide improvement suggestions based on stages - implementation""" + suggestions = [] + + if stage == 'inspect': + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + total_runs = data.get('log_data', {}).get('summary', {}).get('total_runs', 0) + + suggestions.append(f"Inspection Suggestions for {successful_runs}/{total_runs} successful runs:") + + if successful_runs < total_runs * 0.3: + suggestions.append("- Focus on identifying why runs are failing") + suggestions.append("- Check for common parameter ranges in failed runs") + else: + suggestions.append("- Analyze correlations between parameters and objectives") + suggestions.append("- Identify optimal parameter ranges from successful runs") + + elif stage == 'model': + suggestions.append("Modeling Suggestions:") + suggestions.append("- Use surrogate models for early prediction of results") + suggestions.append("- Balance exploration (trying new regions) and exploitation (refining good regions)") + + # Suggest modeling methods based on data volume + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + if successful_runs < 10: + suggestions.append("- With limited data, use simpler models and focus on exploration") + else: + suggestions.append("- With sufficient data, use more complex models and balance exploration/exploitation") + + elif stage == 'agglomerate': + suggestions.append("Parameter Generation Suggestions:") + suggestions.append("- Generate diverse parameter sets to explore different regions") + suggestions.append("- Focus on promising parameter ranges identified in previous stages") + suggestions.append("- Ensure all generated parameters satisfy domain constraints") + + # Suggest strategies based on goals + if self.objective == 'ECP': + suggestions.append("- For ECP, prioritize timing-critical parameters like clk_period and cell padding") + elif self.objective == 'DWL': + suggestions.append("- For DWL, focus on placement and routing parameters") + + return "\n".join(suggestions) + + def _extract_XY_from_data(self, data: Dict) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]: + """Extracting X and Y arrays from data - Reusing logic in analyze_stetrics""" + feature_vectors = [] + objective_values = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and 'metrics' in run: + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + # Use real values, if not available, use proxy values + objective_values.append(obj_values['value'] if obj_values['value'] is not None else obj_values['surrogate']) + + if feature_vectors and objective_values: + return np.array(feature_vectors), np.array(objective_values) + else: + return None, None + + def _format_analysis_result(self, title: str, result: Dict) -> str: + """Format the analysis result as a readable string""" + formatted = f"=== {title} ===\n" + + for key, value in result.items(): + if key == "model_recommendations": + formatted += "\n--- Model Recommendations ---\n" + for rec_key, rec_value in value.items(): + formatted += f"{rec_key}: {rec_value}\n" + elif isinstance(value, (int, float)): + formatted += f"{key}: {value:.4f}\n" + elif isinstance(value, list) and len(value) > 0 and isinstance(value[0], (int, float)): + # Format numerical list + formatted += f"{key}: [{', '.join(f'{v:.4f}' for v in value[:5])}{'...' if len(value) > 5 else ''}]\n" + else: + formatted += f"{key}: {value}\n" + + return formatted + + def _configure_inspection_with_existing(self, config: Dict, data: Dict) -> str: + """Use existing function configuration to check parameters""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Using configuration to run structural analysis + result = inspect_data_structure(X, Y, config) + + response = f"Inspection configured with: {config}\n" + response += "Key findings:\n" + + # Extract key findings + if "linearity_score" in result: + response += f"- Linearity: {result['linearity_score']:.3f}\n" + if "is_nonlinear" in result: + response += f"- Nonlinear: {result['is_nonlinear']}\n" + if "needs_local_models" in result: + response += f"- Needs local models: {result['needs_local_models']}\n" + if "cluster_sizes" in result: + response += f"- Cluster sizes: {result['cluster_sizes']}\n" + + return response + else: + return "No data available for inspection configuration" + + except Exception as e: + return f"Error in inspection configuration: {str(e)}" + + def _analyze_correlations_with_existing(self, params: Dict, data: Dict) -> str: + """Analyze correlation using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain relevant information + config = {"correlation_threshold": params.get('threshold', 0.5)} + result = inspect_data_structure(X, Y, config) + + response = "Feature Correlations Analysis:\n" + + if "feature_importance" in result: + response += "Feature importance (correlation with objective):\n" + for i, importance in enumerate(result["feature_importance"]): + response += f"- {self.parameter_names[i]}: {importance:.3f}\n" + + if "has_correlated_features" in result: + response += f"Has highly correlated features: {result['has_correlated_features']}\n" + if "high_correlation_pairs" in result: + response += f"High correlation pairs: {result['high_correlation_pairs']}\n" + + return response + else: + return "No data available for correlation analysis" + + except Exception as e: + return f"Error in correlation analysis: {str(e)}" + + def _cluster_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Cluster analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain clustering information + result = inspect_data_structure(X, Y, config) + + response = "Cluster Analysis:\n" + + if "cluster_sizes" in result: + response += f"Cluster sizes: {result['cluster_sizes']}\n" + if "cluster_balance" in result: + response += f"Cluster balance: {result['cluster_balance']:.3f}\n" + if "cluster_y_means" in result: + response += "Cluster objective means:\n" + for i, mean in enumerate(result["cluster_y_means"]): + response += f"- Cluster {i}: {mean:.4f}\n" + if "needs_local_models" in result: + response += f"Recommend local models: {result['needs_local_models']}\n" + + return response + else: + return "No data available for cluster analysis" + + except Exception as e: + return f"Error in cluster analysis: {str(e)}" + + def _manifold_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Perform manifold analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_manifold_structure(X, config) + return self._format_analysis_result("Manifold Structure Analysis", result) + else: + return "No data available for manifold analysis" + + except Exception as e: + return f"Error in manifold analysis: {str(e)}" + + def _local_structure_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for local structure analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_local_structure(X, config) + return self._format_analysis_result("Local Structure Analysis", result) + else: + return "No data available for local structure analysis" + + except Exception as e: + return f"Error in local structure analysis: {str(e)}" + + def _get_model_recommendations_from_existing(self, data: Dict) -> str: + """Obtain model recommendations from existing analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_structure(X, Y) + + if "model_recommendations" in result: + recommendations = result["model_recommendations"] + response = "Model Recommendations from Data Analysis:\n" + + for key, value in recommendations.items(): + if key == "feature_weights" and isinstance(value, list): + response += f"{key}: [" + response += ", ".join(f"{w:.3f}" for w in value[:5]) + if len(value) > 5: + response += ", ..." + response += "]\n" + else: + response += f"{key}: {value}\n" + + return response + else: + return "No model recommendations available" + else: + return "No data available for model recommendations" + + except Exception as e: + return f"Error getting model recommendations: {str(e)}" + + + def _configure_model_with_existing(self, config: Dict, data: Dict) -> str: + """Configure the model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Create a model using configuration + kernel_type = config.get('kernel_type', 'matern') + preprocessing = config.get('preprocessing', 'standard') + acquisition = config.get('acquisition', 'ei') + + # Create Preprocessor + preprocessor = create_preprocessor(preprocessing) + + # Create acquisition function + acq_function = create_acquisition_function(acquisition) + + response = f"Model configured successfully:\n" + response += f"- Kernel type: {kernel_type}\n" + response += f"- Preprocessing: {preprocessing}\n" + response += f"- Acquisition function: {acquisition}\n" + response += f"- Data shape: {X.shape}\n" + + # If the amount of data is sufficient, a model can be created for testing + if len(X) >= 2: + model = create_model(X, Y, kernel_type=kernel_type) + response += f"- Model created successfully with {len(X)} samples\n" + else: + response += f"- Insufficient data for model creation (need at least 2 samples, have {len(X)})\n" + + return response + else: + return "No data available for model configuration" + + except Exception as e: + return f"Error in model configuration: {str(e)}" + + def _evaluate_surrogate_with_existing(self, params: Dict, data: Dict) -> str: + """Evaluate the proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Extract proxy values (if any) + surrogate_values = None + if 'surrogates' in data.get('metrics', {}): + surrogate_values = np.array(data['metrics']['surrogates']) + + # Use existing functions to process proxy data + if surrogate_values is not None: + X_processed, y_combined, uncertainty = handle_surrogate_data(X, Y, surrogate_values) + + response = "Surrogate Model Evaluation:\n" + response += f"- Original data points: {len(Y)}\n" + response += f"- Valid target values: {np.sum(~np.isnan(Y))}\n" + response += f"- Surrogate values used: {np.sum(np.isnan(Y))}\n" + response += f"- Combined data points: {len(y_combined)}\n" + + if len(uncertainty) > 0: + response += f"- Average surrogate uncertainty: {np.mean(uncertainty):.4f}\n" + + return response + else: + return "No surrogate data available for evaluation" + else: + return "No data available for surrogate evaluation" + + except Exception as e: + return f"Error in surrogate evaluation: {str(e)}" + + def _select_acquisition_with_existing(self, method: str, data: Dict) -> str: + """Use existing functions to select collection functions""" + try: + # Create a collection function using an existing function + acq_function = create_acquisition_function(method) + + response = f"Acquisition function selected: {method.upper()}\n" + + # Provide explanations for different collection functions + explanations = { + 'ei': "Expected Improvement - balances improvement probability and magnitude", + 'ucb': "Upper Confidence Bound - favors exploration of uncertain regions", + 'pi': "Probability of Improvement - focuses on areas likely to improve", + 'augmented_ei': "Augmented EI - combines EI with exploration bonus" + } + + response += f"Explanation: {explanations.get(method, 'No explanation available')}\n" + + # Provide recommendations based on data characteristics + X, Y = self._extract_XY_from_data(data) + if X is not None and Y is not None: + if len(Y) < 10: + response += "Recommendation: With limited data, consider using UCB for better exploration\n" + else: + response += "Recommendation: With sufficient data, EI or Augmented EI are good choices\n" + + return response + + except Exception as e: + return f"Error in acquisition function selection: {str(e)}" + + def _create_surrogate_model_with_existing(self, config: Dict, data: Dict) -> str: + """Create a proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + kernel_type = config.get('kernel_type', 'matern') + noise_level = config.get('noise_level', 1e-6) + + # Create a model using existing functions + model = create_model(X, Y, noise_level=noise_level, kernel_type=kernel_type) + + response = f"Surrogate Model Created:\n" + response += f"- Kernel: {kernel_type}\n" + response += f"- Data points: {len(X)}\n" + response += f"- Features: {X.shape[1]}\n" + response += f"- Kernel parameters: {model.kernel_}\n" + + # Test model prediction + if len(X) > 0: + predictions, stds = predict_with_model(model, X[:1]) # Test a point + response += f"- Test prediction successful\n" + response += f"- Prediction range: [{predictions[0]:.4f} ± {stds[0]:.4f}]\n" + + return response + else: + return "No data available for model creation" + + except Exception as e: + return f"Error in surrogate model creation: {str(e)}" + + def _evaluate_timing_model_with_existing(self, data: Dict) -> str: + """Evaluate timing models using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate timing models using existing functions + results = evaluate_timing_model(context) + + response = "Timing Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in timing model evaluation: {str(e)}" + + def _evaluate_wirelength_model_with_existing(self, data: Dict) -> str: + """Evaluate the wire length model using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate the wire length model using existing functions + results = evaluate_wirelength_model(context) + + response = "Wirelength Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in wirelength model evaluation: {str(e)}" + + def _generate_parameters_with_existing(self, count: int, data: Dict) -> str: + """Generate parameters using existing functions""" + try: + if count <= 0 or count > 50: + return "Error: count must be between 1 and 50" + + # Obtain parameter dimensions + n_dims = len(self.parameter_names) + + # Use existing Latin hypercube sampling + samples = latin_hypercube(count, n_dims) + + response = f"Parameter Generation using Latin Hypercube:\n" + response += f"- Samples generated: {count}\n" + response += f"- Parameter dimensions: {n_dims}\n" + response += f"- Sampling method: Latin Hypercube\n" + + # Display parameter range information + response += "\nParameter Ranges:\n" + for i, param in enumerate(self.parameter_names): + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + response += f"- {param}: [{min_val}, {max_val}] ({constraint['type']})\n" + + return response + + except Exception as e: + return f"Error in parameter generation: {str(e)}" + + def _latin_hypercube_sampling_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for Latin hypercube sampling""" + try: + n_points = config.get('n_points', 10) + n_dims = len(self.parameter_names) + + # Use the existing Latin hypercube sampling function + samples = latin_hypercube(n_points, n_dims) + + response = f"Latin Hypercube Sampling:\n" + response += f"- Points: {n_points}\n" + response += f"- Dimensions: {n_dims}\n" + response += f"- Sample shape: {samples.shape}\n" + + # Display sampling statistics + response += f"- Sample range: [{samples.min():.3f}, {samples.max():.3f}]\n" + response += f"- Sample mean: {samples.mean():.3f}\n" + response += f"- Sample std: {samples.std():.3f}\n" + + return response + + except Exception as e: + return f"Error in Latin hypercube sampling: {str(e)}" + + def _configure_selection_with_existing(self, config: Dict, data: Dict) -> str: + """Configure selection strategy using existing functions""" + try: + method = config.get('method', 'hybrid') + quality_weight = config.get('quality_weight', 0.7) + uncertainty_bonus = config.get('uncertainty_bonus', 0.2) + n_points = config.get('n_points', 10) + + response = f"Selection Strategy Configured:\n" + response += f"- Method: {method}\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Uncertainty bonus: {uncertainty_bonus}\n" + response += f"- Points to select: {n_points}\n" + + # Provide explanations for different methods + method_descriptions = { + "kmeans": "K-means clustering - selects best point from each cluster", + "hybrid": "Hybrid approach - balances quality and diversity", + "entropy": "Entropy-based - maximizes information diversity", + "graph": "Graph-based - uses network centrality measures" + } + + response += f"Method description: {method_descriptions.get(method, 'No description')}\n" + + return response + + except Exception as e: + return f"Error in selection configuration: {str(e)}" + + + def _create_quality_scores_with_existing(self, config: Dict, data: Dict) -> str: + """Create a quality score using an existing function""" + try: + # Extract necessary information from data + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Simulation model predictions and uncertainties (in practical use, these should come from real models) + model_predictions = Y # Using real values as a proxy for prediction + model_uncertainties = np.ones_like(Y) * 0.1 # Simulate uncertainty + + # Create a quality score using an existing function + quality_scores = create_quality_scores(X, Y, model_predictions, model_uncertainties) + + response = "Quality Scores Created:\n" + response += f"- Data points: {len(X)}\n" + response += f"- Quality score range: [{quality_scores.min():.4f}, {quality_scores.max():.4f}]\n" + response += f"- Quality score mean: {quality_scores.mean():.4f}\n" + response += f"- Quality score std: {quality_scores.std():.4f}\n" + + response += f"- First 5 quality scores: {quality_scores[:5].tolist()}\n" + + if 'selection_data' not in data: + data['selection_data'] = {} + data['selection_data']['quality_scores'] = quality_scores + data['selection_data']['X'] = X + data['selection_data']['Y'] = Y + + return response + else: + return "No data available for quality score creation" + + except Exception as e: + return f"Error in quality score creation: {str(e)}" + + def _select_points_with_existing(self, config: Dict, data: Dict) -> str: + """_select_points_with_existing""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + method = config.get('method', 'hybrid') + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + selection_config = { + "quality_weight": quality_weight, + "uncertainty_bonus": config.get('uncertainty_bonus', 0.2) + } + + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points, + config=selection_config + ) + + response = f"Points Selected using {method.upper()} method:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Selected quality scores: {selected_qualities.tolist()}\n" + response += f"- Average quality of selected: {selected_qualities.mean():.4f}\n" + + # store selection data + data['selection_data']['selected_indices'] = selected_indices + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in point selection: {str(e)}" + + def _compare_selection_methods_with_existing(self, config: Dict, data: Dict) -> str: + """compare selection methods with existing(""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 5) + methods = ['kmeans', 'hybrid', 'entropy', 'graph'] + + response = "Selection Method Comparison:\n" + response += f"- Comparing {len(methods)} methods\n" + response += f"- Points to select: {n_points}\n\n" + + for method in methods: + try: + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points + ) + + selected_qualities = quality_scores[selected_indices] + + response += f"**{method.upper()}**:\n" + response += f" - Selected indices: {selected_indices.tolist()}\n" + response += f" - Avg quality: {selected_qualities.mean():.4f}\n" + response += f" - Quality range: [{selected_qualities.min():.4f}, {selected_qualities.max():.4f}]\n" + + except Exception as e: + response += f"**{method.upper()}**: Error - {str(e)}\n" + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in method comparison: {str(e)}" + + def _kmeans_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using K-means selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using K-means selecting function + selected_indices = kmeans_select(X, quality_scores, n_points) + + response = "K-means Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + response += f"- Quality diversity: {selected_qualities.std():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'kmeans' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in K-means selection: {str(e)}" + + def _hybrid_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing hybrid selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + distance_matrix = cdist(X, X) + + # using hybrid_select function + selected_indices = hybrid_select( + X, quality_scores, distance_matrix, + n_points, quality_weight + ) + + response = "Hybrid Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + selected_points = X[selected_indices] + min_distances = np.min(cdist(selected_points, selected_points) + np.eye(len(selected_points)) * 1e6, axis=1) + response += f"- Minimum inter-point distance: {min_distances.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'hybrid' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in hybrid selection: {str(e)}" + + def _entropy_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing entropy selecting methods""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using entropy selecting function + selected_indices = entropy_select(X, quality_scores, n_points) + + response = "Entropy-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'entropy' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in entropy selection: {str(e)}" + + def _graph_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing graph selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using graph selecting function + selected_indices = graph_select(X, quality_scores, n_points) + + response = "Graph-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'graph' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in graph selection: {str(e)}" + + + def _validate_parameters_tool(self, params: Dict) -> str: + validation_results = [] + + for param_name, value in params.items(): + if param_name in self.param_constraints: + constraint = self.param_constraints[param_name] + min_val, max_val = constraint['range'] + param_type = constraint['type'] + + if value < min_val or value > max_val: + validation_results.append(f" {param_name}={value} outside range [{min_val}, {max_val}]") + else: + validation_results.append(f" {param_name}={value} within valid range") + + if self._validate_domain_constraints(params): + validation_results.append("Domain constraints satisfied") + else: + validation_results.append("Domain constraints violated") + + return "Parameter Validation:\n" + "\n".join(validation_results) + def _load_config(self) -> Dict[str, Any]: """Load the configuration from 'opt_config.json'.""" @@ -249,41 +1423,40 @@ def _load_sdc_context(self) -> Dict[str, Any]: return sdc_context + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: - """Generate LLM prompt for different stages""" - # Include parameter constraints in the prompt constraints_text = "Parameter Constraints:\n" for param, info in self.param_constraints.items(): param_type = info['type'] param_range = info['range'] constraints_text += f"- {param} ({param_type}, range: {param_range})\n" - # Construct the prompt based on the stage - if stage == 'inspect': - prompt = ( + tool_instructions = { + 'inspect': ( f"**Stage: Inspect**\n" "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" - f"Data to analyze:\n{json.dumps(data, indent=2)}\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" "Please analyze the data and provide insights on:\n" "1. Key patterns in successful vs unsuccessful runs.\n" "2. Parameter ranges that appear promising.\n" "3. Any timing or wirelength trends.\n" "4. Recommendations for subsequent runs.\n" - ) - elif stage == 'model': - prompt = ( + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( f"**Stage: Model**\n" "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" - f"Data for modeling:\n{json.dumps(data, indent=2)}\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" "Please suggest:\n" "1. Appropriate modeling techniques.\n" "2. Key parameters to focus on.\n" "3. Surrogate model recommendations.\n" "4. Acquisition function choices.\n" - ) - elif stage == 'agglomerate': - prompt = ( + ), + + 'agglomerate': ( f"**Stage: Agglomerate**\n" "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" @@ -291,181 +1464,394 @@ def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: "Each parameter set should be a dictionary with parameter names and their suggested values.\n" "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" ) - else: - prompt = ( - f"**Stage: {stage.capitalize()}**\n" - f"Data:\n{json.dumps(data, indent=2)}\n\n" - "Please provide guidance based on the above data.\n" - ) + } + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** - return prompt + {stage_contexts.get(stage, '')} + + {tool_instructions.get(stage, '')} + + **Important: Use only tool calls and do not generate text replies!** + """ + + # ========= Splicing RAG ========= + rag_context = "" + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + + # Step 1: Extract error information + error_summary = "" + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + if all_errors: + # Retrieve the most recent or frequent errors + top_errors = all_errors[-3:] # Last 3 posts + error_summary = "\n".join(top_errors) + print(f"[DEBUG] Detected {len(all_errors)} error messages. Sample:\n{error_summary}") + + # Step 2: Construct RAG query + if error_summary: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"The recent optimization runs failed with errors:\n{error_summary}\n\n" + "Retrieve relevant OpenROAD documentation, known failure modes, and " + "potential parameter tuning suggestions that may fix these issues." + ) + else: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + + # Step 3: Execute search + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict, + ) + + if isinstance(rag_context, dict): # If returning dict + print(f"[DEBUG] RAG Retrieved {len(rag_context.get('docs', []))} related entries.") + for doc in rag_context.get("docs", [])[:3]: + print(f" ↳ {doc['title']} (score={doc['score']:.3f}) from {doc['source']}") + retrieved_text = rag_context.get("content", "") + else: + retrieved_text = rag_context + + # Step 4: add to prompt + if retrieved_text.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{retrieved_text}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + + if all_errors: + error_summary = "\n".join(all_errors[-5:]) # The last 5 errors + prompt += f""" + + ### Detected Run Errors + {error_summary} + + The model must now act as an **EDA Debugging Assistant**. + Using the retrieved documentation and knowledge, analyze the errors above and: + 1. Identify the root causes of each error (e.g., tool misconfiguration, parameter overflow, timing issues, etc.) + 2. Suggest **specific parameter changes or flow adjustments** to prevent these errors. + 3. Indicate whether the error is likely due to constraints, routing congestion, or timing margin. + 4. Provide a short explanation for each suggestion. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + + """ + print("[DEBUG] Added error-fix section to prompt.") + def _collect_recent_errors(self, data: Dict[str, Any], max_errors=5) -> str: + errors = [] + for run in data.get("log_data", {}).get("runs", []): + if run.get("errors"): + errors.extend(run["errors"]) + print(f"[DEBUG] Found total {len(errors)} errors in all runs.") + return "\n".join(errors[-max_errors:]) if errors else "No errors detected." def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: - """Call Claude to get recommendations for optimization parameters""" - print(f"\n=== Calling LLM for {stage} stage ===") - - # Hardcode API key - api_key = #PUT YOUR KEY HERE - - client = anthropic.Anthropic(api_key=api_key) - - tools = [ - { - "name": "configure_inspection", - "description": "Configure data inspection parameters", - "input_schema": { - "type": "object", - "properties": { - "n_clusters": { - "type": "integer", - "description": "Number of clusters for structure analysis", - "minimum": 2, - "maximum": 10 - }, - "correlation_threshold": { - "type": "number", - "description": "Threshold for considering correlations significant", - "minimum": 0, - "maximum": 1 - } - }, - "required": ["n_clusters", "correlation_threshold"] - } - }, - { - "name": "configure_model", - "description": "Configure modeling approach", - "input_schema": { - "type": "object", - "properties": { - "kernel_type": { - "type": "string", - "enum": ["rbf", "matern", "rational"], - "description": "Type of kernel to use" - }, - "preprocessing": { - "type": "string", - "enum": ["standard", "robust", "none"], - "description": "Type of preprocessing to apply" - }, - "acquisition": { - "type": "string", - "enum": ["ei", "ucb", "pi"], - "description": "Acquisition function to use" - }, - "surrogate_weight": { - "type": "number", - "description": "Weight to give surrogate values", - "minimum": 0, - "maximum": 1 - } - }, - "required": ["kernel_type", "preprocessing", "acquisition", "surrogate_weight"] - } - }, - { - "name": "configure_selection", - "description": "Configure point selection strategy", - "input_schema": { - "type": "object", - "properties": { - "method": { - "type": "string", - "enum": ["entropy", "kmeans", "hybrid", "graph"], - "description": "Selection method to use" - }, - "quality_weight": { - "type": "number", - "description": "Weight between quality and diversity", - "minimum": 0, - "maximum": 1 - }, - "uncertainty_bonus": { - "type": "number", - "description": "Weight for uncertainty in quality scores", - "minimum": 0, - "maximum": 1 - } - }, - "required": ["method", "quality_weight", "uncertainty_bonus"] - } + # """Call Claude to get recommendations for optimization parameters""" + # print(f"\n=== Calling LLM for {stage} stage ===") + """Call LLM to get recommendations for optimization parameters using react framework""" + print(f"\n=== Calling LLM with ReAct framework for {stage} stage ===") + + try: + react_prompt = self._generate_react_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(react_prompt) + print("========================") + available_tools = self._create_react_tools(stage, data) + + react_result = self.react_framework.run_react_cycle( + initial_prompt=react_prompt, + available_tools=available_tools, + max_steps=3, + temperature=0.1 + ) + # === If an error occurs, enter Debug mode === + if "log_data" in data and any(run.get("errors") for run in data["log_data"].get("runs", [])): + print("\n[DEBUG] Detected errors in previous runs. Invoking Debug Assistant mode...") + + # Collect error information + all_errors = [] + for run in data["log_data"]["runs"]: + if run.get("errors"): + all_errors.extend(run["errors"]) + error_text = "\n".join(all_errors[-5:]) # Recent entries + + # Construct a Debug Prompt + debug_prompt = f""" + You are now an **EDA Debugging Expert**. + Based on the following OpenROAD errors and RAG documentation, analyze and provide concrete repair suggestions. + + Errors Detected: + {error_text} + + Please identify: + 1. Root cause of each error. + 2. Specific parameter changes (e.g., in floorplan, CTS, or routing stages) that could fix the issue. + 3. Whether this issue is due to timing, congestion, or setup misconfiguration. + 4. One short explanation per fix. + + Return your answer in **JSON format** like: + {{ + "error_analysis": [ + {{ + "error": "...", + "cause": "...", + "fix": "...", + "params_to_adjust": {{"param_name": "new_value"}} + }} + ] + }} + """ + + # Call LLM to output repair suggestions + debug_result = self.react_framework.run_react_cycle( + initial_prompt=debug_prompt, + available_tools=available_tools, + max_steps=2, + temperature=0.2 + ) + + print("\n[DEBUG] LLM Debug Assistant Result:") + print(debug_result.get("final_answer", "")) + + # Save repair suggestions to the main results + react_result["error_fix_suggestions"] = debug_result.get("final_answer", "") + # Write files for manual viewing + with open("logs/error_fix_suggestions.json", "w") as f: + f.write(debug_result.get("final_answer", "")) + print(f"\n=== ReAct Cycle Completed ===") + print(f"Completed steps: {react_result.get('completed_steps', 0)}/{react_result.get('max_steps', 8)}") + print(f"Final Answer: {react_result['final_answer']}") + + configs = self._parse_react_final_answer(react_result["final_answer"], stage) + + if react_result.get('reasoning_history'): + print(f"\n=== Reasoning History ({len(react_result['reasoning_history'])} steps) ===") + for step in react_result['reasoning_history']: + print(f"Step {step['step']}: {step.get('thought', 'No thought')}") + + print(f"Returning config for stage '{stage}': {configs}") + return configs + + except Exception as e: + print(f"Error in LLM call for stage {stage}: {e}") + default_config = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'agglomerate': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} } - ] + return default_config.get(stage, {}) + - # Get data summaries - if stage == 'inspect': - print("Generating data distribution and structure summaries...") - # Extract X and Y from successful runs if available - X = [] - Y = [] - if 'log_data' in data and 'runs' in data['log_data']: - for run in data['log_data']['runs']: - if run['success'] and 'metrics' in run: - obj = self._calculate_objective(run) - if obj['value'] is not None or obj['surrogate'] is not None: - # Use parameters as X - params = [] - for param in self.param_constraints.keys(): - params.append(float(run.get('parameters', {}).get(param, 0))) - X.append(params) - # Use objective as Y - Y.append(obj['value'] if obj['value'] is not None else obj['surrogate']) - - if X and Y: - dist_summary = inspect_data_distribution(np.array(X), np.array(Y)) - struct_summary = inspect_data_structure(np.array(X)) - else: - print("No successful runs found, using empty summaries") - dist_summary = {} - struct_summary = {} + def _generate_react_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """generate prompts of ReAct framework""" + + stage_descriptions = { + 'inspect': ( + "You are an expert EDA optimization analyst. Analyze the optimization run data to identify patterns " + "and insights. Use the available tools to examine data distributions, correlations, and successful " + "parameter ranges. Your goal is to understand what makes runs successful and provide recommendations " + "for the modeling stage." + ), + 'model': ( + "You are an expert machine learning engineer for EDA optimization. Based on the inspection results, " + "configure the modeling approach for Bayesian optimization. Consider kernel selection, acquisition " + "functions, and surrogate modeling strategies. Balance exploration and exploitation based on the data." + ), + 'agglomerate': ( + "You are an expert parameter optimization specialist. Generate new parameter combinations for the " + "next optimization iteration. Use insights from previous stages to focus on promising regions while " + "maintaining diversity. Ensure all parameters satisfy the domain constraints." + ) + } + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + constraints_text += f"- {param} ({info['type']}, range: {info['range']})\n" + + react_format_instructions = """ +**ReAct Framework Instructions - MUST FOLLOW THIS FORMAT:** + +1. **Thought**: Analyze the current situation and decide what to do next +2. **Action**: Choose one tool from the available tools +3. **Action Input**: Provide the appropriate input for the chosen tool +4. **Observation**: Wait for the tool's response, then continue reasoning + +**Available Tools**: You have access to various analysis tools. Use them to gather information before making decisions. + +**DO NOT include Final Answer until you have completed all necessary analysis.** +**DO NOT predict or simulate tool observations.** +**You will receive actual Observation from tools before continuing.** + +Only after proper analysis: +**Final Answer Format**: Only when you have completed your analysis, provide: +Final Answer: {your_configuration_here} + +**Example**: +Thought: I need to understand the data patterns first. Let me analyze the success rates. +Action: analyze_data_patterns +Action Input: {} +Observation: [Tool response...] +Thought: Now I need to check parameter correlations... +Action: analyze_correlations +Action Input: {} +Observation: [Tool response...] +Final Answer: {"n_clusters": 5, "correlation_threshold": 0.7} +""" + + prompt = f""" + {stage_descriptions[stage]} + + **Current Stage**: {stage.upper()} + **Objective**: {self.objective} + **Platform**: {self.platform} + **Design**: {self.design} + + **Available Data**: + - Total runs: {data.get('log_data', {}).get('summary', {}).get('total_runs', 0)} + - Successful runs: {data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)} + - Failed runs: {data.get('log_data', {}).get('summary', {}).get('failed_runs', 0)} + + {constraints_text} + {react_format_instructions} + + Begin your analysis: + """ + + rag_context = "" + # ======== extract errors ======== + error_summary = self._collect_recent_errors(data) + if error_summary and "No errors" not in error_summary: + print("[DEBUG] RAG: Detected error summary, adding error analysis prompt...") + prompt += f""" + + ### Detected Run Errors + {error_summary} + + You are now acting as an **EDA Debugging Assistant**. + Analyze the errors above and: + 1. Identify the root causes. + 2. Suggest specific parameter changes. + 3. Indicate whether the error is due to timing, routing, or constraints. + 4. Provide short explanations for each. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + """ else: - dist_summary = {} - struct_summary = {} - - # Generate context message - context_message = self._generate_llm_prompt(stage, data) - print(f"Generated prompt with context for {stage}") - - print("Making LLM API call...") - response = client.messages.create( - model="claude-3-sonnet-20240229", - max_tokens=2048, - tools=tools, - messages=[{ - "role": "user", - "content": context_message - }] - ) + print("[DEBUG] No errors found in logs for this stage.") + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict + ) + print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + if rag_context.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{rag_context}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" - # Extract configurations + return prompt + + def _parse_react_final_answer(self, final_answer: str, stage: str) -> Dict[str, Any]: + """parse react final answer""" + + default_configs = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'selection': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + configs = {} - print("\nReceived tool calls from LLM:") - for block in response.content: - if block.type == 'tool_use': - print(f"- {block.name}: {block.input}") - if block.name == 'configure_inspection': - configs['inspection'] = block.input - elif block.name == 'configure_model': - configs['model'] = block.input - elif block.name == 'configure_selection': - configs['selection'] = block.input - - # Add default configs if missing - for key, default in [ - ('inspection', {"n_clusters": 5, "correlation_threshold": 0.5}), - ('model', {"kernel_type": "matern", "preprocessing": "robust", - "acquisition": "ei", "surrogate_weight": 0.8}), - ('selection', {"method": "hybrid", "quality_weight": 0.7, - "uncertainty_bonus": 0.2}) - ]: - if key not in configs: - print(f"Warning: No {key} config from LLM, using defaults: {default}") - configs[key] = default + + if final_answer and "Reached maximum steps" not in final_answer: + try: + json_match = re.search(r'\{.*\}', final_answer, re.DOTALL) + if json_match: + extracted_config = json.loads(json_match.group()) + configs[stage] = extracted_config + print(f"✓ Extracted configuration from ReAct response: {extracted_config}") + else: + configs[stage] = default_configs.get(stage, {}) + print(f"⚠ Using default configuration for {stage} stage") + except Exception as e: + print(f"Error parsing ReAct final answer: {e}") + configs[stage] = default_configs.get(stage, {}) + else: + configs[stage] = default_configs.get(stage, {}) + print(f"ReAct failed to produce answer, using default for {stage}") return configs def run_iteration(self, num_runs: int) -> None: - """Run a complete iteration of the optimization workflow""" + """Run a complete iteration of the optimization workflow using react framework""" print(f"\n=== Starting optimization iteration for {self.platform}/{self.design} ===") print(f"Objective: {self.objective}") print(f"Number of runs requested: {num_runs}") @@ -477,25 +1863,29 @@ def run_iteration(self, num_runs: int) -> None: f"{log_data['summary']['successful_runs']} successful") # Get LLM recommendations for inspection and analysis - print("\nGetting LLM recommendations for inspection...") + # print("\nGetting LLM recommendations for inspection...") + print("\nGetting LLM recommendations with ReAct framework for inspection...") inspect_configs = self._call_llm('inspect', { 'log_data': log_data, 'initial_params': self.initial_params, 'sdc_context': self.sdc_context }) - print(f"LLM inspection config: {inspect_configs['inspection']}") + inspection_config = inspect_configs.get('inspect', {}) + print(f"React inspection config: {inspection_config}") # Step 2: Analyze metrics with LLM config - print("\nStep 2: Analyzing metrics...") + print("\nStep 2: Analyzing metrics ...") metrics = self.analyze_metrics( log_data, - n_clusters=inspect_configs['inspection']['n_clusters'], - correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + # n_clusters=inspect_configs['inspection']['n_clusters'], + n_clusters=inspection_config.get('n_clusters', 5), + # correlation_threshold=inspect_configs['inspection']['correlation_threshold'] + correlation_threshold=inspection_config.get('correlation_threshold', 0.5) ) print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") - # Get LLM recommendations for modeling based on inspection results - print("\nGetting LLM recommendations for modeling...") + # Get LLM recommendations for modeling based on inspection results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for modeling...") model_configs = self._call_llm('model', { 'log_data': log_data, 'metrics': metrics, @@ -503,20 +1893,25 @@ def run_iteration(self, num_runs: int) -> None: 'sdc_context': self.sdc_context, 'inspection_results': inspect_configs }) - print(f"LLM model config: {model_configs['model']}") + model_config = model_configs.get('model', {}) + print(f"LLM model config: {model_config}") # Step 3: Evaluate models with LLM config print("\nStep 3: Evaluating models...") model_results = self.evaluate_models( log_data, metrics, - kernel_type=model_configs['model']['kernel_type'], - preprocessing=model_configs['model']['preprocessing'], - acquisition=model_configs['model']['acquisition'], - surrogate_weight=model_configs['model']['surrogate_weight'] + # kernel_type=model_configs['model']['kernel_type'], + model_config.get('kernel_type', 'matern'), + # preprocessing=model_configs['model']['preprocessing'], + preprocessing=model_config.get('preprocessing', 'robust'), + # acquisition=model_configs['model']['acquisition'], + acquisition=model_config.get('acquisition', 'ei'), + # surrogate_weight=model_configs['model']['surrogate_weight'] + surrogate_weight=model_config.get('surrogate_weight', 0.8) ) - # Get LLM recommendations for parameter selection based on all previous results - print("\nGetting LLM recommendations for parameter selection...") + # Get LLM recommendations for parameter selection based on all previous results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for parameter selection...") selection_configs = self._call_llm('agglomerate', { 'log_data': log_data, 'metrics': metrics, @@ -526,20 +1921,26 @@ def run_iteration(self, num_runs: int) -> None: 'inspection_results': inspect_configs, 'model_configs': model_configs }) - print(f"LLM selection config: {selection_configs['selection']}") + selection_config = selection_configs.get('agglomerate', {}) + print(f"LLM selection config: {selection_config}") # Step 4: Generate parameters with LLM config print("\nStep 4: Generating parameters...") self.generate_parameters( log_data, metrics, model_results, num_runs, - selection_method=selection_configs['selection']['method'], - quality_weight=selection_configs['selection']['quality_weight'], - uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + # selection_method=selection_configs['selection']['method'], + # quality_weight=selection_configs['selection']['quality_weight'], + # uncertainty_bonus=selection_configs['selection']['uncertainty_bonus'] + selection_method=selection_config.get('method', 'hybrid'), + quality_weight=selection_config.get('quality_weight', 0.7), + uncertainty_bonus=selection_config.get('uncertainty_bonus', 0.2) ) - + def inspect_logs(self) -> Dict[str, Any]: - """Step 1: Inspect all logs so far""" - log_dir = f"logs/{self.platform}/{self.design}" + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + log_data = { 'runs': [], 'summary': { @@ -548,25 +1949,62 @@ def inspect_logs(self) -> Dict[str, Any]: 'failed_runs': 0 } } - - # Ensure log directory exists + if not os.path.exists(log_dir): return log_data - - # Process each log file - for log_file in os.listdir(log_dir): - if log_file.endswith('.log'): - run_data = process_log_file(os.path.join(log_dir, log_file)) - log_data['runs'].append(run_data) - - # Update summary - log_data['summary']['total_runs'] += 1 - if run_data['success']: - log_data['summary']['successful_runs'] += 1 - else: - log_data['summary']['failed_runs'] += 1 - + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + return log_data + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: """Step 2: Analyze metrics from log data with improved analysis""" @@ -658,6 +2096,7 @@ def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation return metrics + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: """Step 3: Use improved model functions to evaluate parameter quality""" @@ -1053,4 +2492,4 @@ def main(): workflow.run_iteration(num_runs) # Use the run_iteration method instead of individual steps if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/flow-Agent/optimize_dual.py b/flow-Agent/optimize_dual.py new file mode 100644 index 0000000..f762ed1 --- /dev/null +++ b/flow-Agent/optimize_dual.py @@ -0,0 +1,2593 @@ +#!/usr/bin/env python3 +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random +from rag.util import answerWithRAG +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from sentence_transformers import SentenceTransformer +import torch +from pathlib import Path +from openai import OpenAI +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * +import warnings +warnings.filterwarnings("ignore", category=RuntimeWarning) + +print("Python executable:", sys.executable) +print("sys.path:", sys.path[:3]) +print("Current working dir:", os.getcwd()) + +for pkg in ["anthropic", "sentence_transformers", "torch", "openai"]: + try: + __import__(pkg) + print(f" Imported {pkg}") + except ImportError as e: + print(f" Failed to import {pkg}: {e}") + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + print(f"File size: {len(content)} characters") + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + # === Inject a simulated error for testing RAG debugging === + # if "run3" in log_path: # 👈 你可以换成任意 run,比如 run1 或 run2 + # fake_error = "[ERROR] TEST_SIM: Simulated routing congestion failure" + # print(f"[DEBUG] Injected simulated error in {log_path}: {fake_error}") + # run_data['errors'].append(fake_error) + # run_data['success'] = False + + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str], filename: str = "") -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + # If any real error lines were found, this file is a failure indicator + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully', + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + + +class ReActFramework: + """ReAct framework implementation""" + + def __init__(self, client, model_name="DeepSeek-V3"): + self.client = client + self.model_name = model_name + self.conversation_history = [] + + def add_to_history(self, role: str, content: str): + """add conversation history""" + self.conversation_history.append({"role": role, "content": content}) + + def clear_history(self): + """clear conversation history""" + self.conversation_history = [] + + def extract_thought_action(self, response: str) -> Tuple[str, str, str]: + """ + Extract Thought, Action, and Action Input from LLM responses + Format: Thought:... Action:... Action Input: ... + """ + thought = "" + action = "" + action_input = "" + + # Extract Thought + thought_match = re.search(r'Thought:\s*(.*?)(?=\nAction:|$)', response, re.DOTALL) + if thought_match: + thought = thought_match.group(1).strip() + + # Extract Action + action_match = re.search(r'Action:\s*(\w+)', response) + if action_match: + action = action_match.group(1).strip() + + # Extract Action Input + action_input_match = re.search(r'Action Input:\s*(.*?)(?=\nObservation:|$)', response, re.DOTALL) + if action_input_match: + action_input = action_input_match.group(1).strip() + # Try to parse JSON + try: + if action_input.startswith('{') or action_input.startswith('['): + action_input = json.loads(action_input) + except: + pass # Maintain the string format + + if "Final Answer:" in response and ("Action:" in response or "Observation:" in response): + + response = response.split("Final Answer:")[0] + print("Removed premature Final Answer from response") + + return thought, action, action_input + + def execute_action(self, action: str, action_input: Any, available_tools: Dict) -> str: + """Execute tool call and return observation results""" + if action in available_tools: + try: + result = available_tools[action](action_input) + return f"Action executed successfully. Result: {result}" + except Exception as e: + return f"Action execution failed: {str(e)}" + else: + return f"Unknown action: {action}. Available actions: {list(available_tools.keys())}" + + def run_react_cycle(self, + initial_prompt: str, + available_tools: Dict, + max_steps: int = 5, + temperature: float = 0.1) -> Dict[str, Any]: + """ + Run ReAct loop + + Args: + initial_prompt: Initial prompt + available_tools: Available tool function dictionary + max_steps: Maximum reasoning steps + temperature: temperature parameter + + Returns: + a dictionary containing the final result and the reasoning history + """ + self.clear_history() + self.add_to_history("user", initial_prompt) + + history = [] + final_answer = None + completed_steps = 0 + + for step in range(max_steps): + print(f"\n=== ReAct Step {step + 1}/{max_steps} ===") + completed_steps = step + 1 + + # Call LLM to obtain response + try: + response = self.client.chat.completions.create( + model=self.model_name, + messages=self.conversation_history, + temperature=temperature, + max_tokens=1024 + ) + + llm_response = response.choices[0].message.content + print(f"LLM Response: {llm_response}") + except Exception as e: + print(f"Error calling LLM: {e}") + llm_response = f"Error in LLM call: {e}" + + # Extract Thought, Action, Action Input + thought, action, action_input = self.extract_thought_action(llm_response) + + step_data = { + "step": step + 1, + "thought": thought, + "action": action, + "action_input": action_input, + "llm_response": llm_response + } + + # Check if it is the final answer + final_answer_detected = False + if "Final Answer:" in llm_response: + final_answer_match = re.search(r'Final Answer:\s*(.*?)$', llm_response, re.DOTALL) + if final_answer_match: + final_answer = final_answer_match.group(1).strip() + step_data["final_answer"] = final_answer + final_answer_detected = True + print(f"✓ Final answer detected at step {step + 1}") + + observation = "" + # Execute actions and obtain observation results + if action and not final_answer_detected: + observation = self.execute_action(action, action_input, available_tools) + step_data["observation"] = observation + + # Update conversation history + self.add_to_history("assistant", llm_response) + self.add_to_history("user", f"Observation: {observation}") + + print(f"Thought: {thought}") + print(f"Action: {action}") + print(f"Action Input: {action_input}") + print(f"Observation: {observation}") + else: + if not final_answer_detected: + # If there is no clear action, it may be during the reasoning process + self.add_to_history("assistant", llm_response) + step_data["observation"] = "No action taken - continuing reasoning" + observation = "No action taken" + else: + # If it is the final answer, no further action is required + step_data["observation"] = "Final answer provided - cycle complete" + observation = "Final answer provided" + + history.append(step_data) + + if final_answer_detected: + print(f" ReAct cycle completed at step {step + 1} with final answer") + break + + # Check if it should end early + if step >= max_steps - 1: + final_answer = f"Reached maximum steps ({max_steps}) without final answer" + print(f" Reached maximum steps without final answer") + break + + if final_answer is None: + final_answer = "No final answer produced" + + return { + "final_answer": final_answer, + "reasoning_history": history, + "success": final_answer is not None and "Reached maximum steps" not in final_answer and "No final answer" not in final_answer, + "completed_steps": completed_steps, + "max_steps": max_steps + } + + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + emb_np, docs, docsDict = load_embeddings_and_docs() + self.rag_embeddings = torch.tensor(emb_np).cpu() + self.rag_docs = docs + self.rag_docsDict = docsDict + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + model_path = model_path.resolve() + # self.rag_model = SentenceTransformer(str(model_path)) + self.rag_model = SentenceTransformer(str(model_path), device='cpu') + + self.react_framework = ReActFramework( + client=OpenAI( + base_url="https://ai.gitee.com/v1", + # api_key=" ", + api_key=" ", + ), + model_name="DeepSeek-V3" + ) + # Secondary supervisor model for dual-LLM flow. All values can be overridden via env variables. + self.supervisor_client = OpenAI( + base_url=os.environ.get("SUPERVISOR_BASE_URL", "https://ai.gitee.com/v1"), + api_key=os.environ.get("SUPERVISOR_API_KEY", " "), + ) + self.supervisor_model_name = os.environ.get("SUPERVISOR_MODEL", "DeepSeek-V3") + self.supervision_feedback: str = "" + + def _create_react_tools(self, stage: str, data: Dict[str, Any]) -> Dict: + """Create available utility functions for different stages""" + + base_tools = { + "analyze_data_distribution": lambda x: self._call_existing_distribution_analysis(data), + "analyze_data_structure": lambda x: self._call_existing_structure_analysis(data), + "evaluate_parameter_ranges": lambda x: self._evaluate_parameter_ranges(data), + "check_constraints": lambda x: self._check_constraints_compliance(data), + "suggest_improvements": lambda x: self._suggest_improvements(stage, data), + } + + if stage == 'inspect': + inspection_tools = { + "configure_inspection": lambda config: self._configure_inspection_with_existing(config, data), + "analyze_correlations": lambda params: self._analyze_correlations_with_existing(params, data), + "cluster_analysis": lambda config: self._cluster_analysis_with_existing(config, data), + "manifold_analysis": lambda config: self._manifold_analysis_with_existing(config, data), + "local_structure_analysis": lambda config: self._local_structure_analysis_with_existing(config, data), + } + base_tools.update(inspection_tools) + + elif stage == 'model': + modeling_tools = { + "configure_model": lambda config: self._configure_model_with_existing(config, data), + "evaluate_surrogate": lambda params: self._evaluate_surrogate_with_existing(params, data), + "select_acquisition": lambda method: self._select_acquisition_with_existing(method, data), + "create_surrogate_model": lambda config: self._create_surrogate_model_with_existing(config, data), + "evaluate_timing_model": lambda x: self._evaluate_timing_model_with_existing(data), + "evaluate_wirelength_model": lambda x: self._evaluate_wirelength_model_with_existing(data), + "get_model_recommendations": lambda x: self._get_model_recommendations_from_existing(data), + } + base_tools.update(modeling_tools) + + elif stage == 'agglomerate': + selection_tools = { + "configure_selection": lambda config: self._configure_selection_with_existing(config, data), + "generate_parameters": lambda count: self._generate_parameters_with_existing(count, data), + "validate_parameters": lambda params: self._validate_parameters_tool(params), + "latin_hypercube_sampling": lambda config: self._latin_hypercube_sampling_with_existing(config, data), + "create_quality_scores": lambda config: self._create_quality_scores_with_existing(config, data), + "select_points": lambda config: self._select_points_with_existing(config, data), + "compare_selection_methods": lambda config: self._compare_selection_methods_with_existing(config, data), + "kmeans_selection": lambda config: self._kmeans_selection_with_existing(config, data), + "hybrid_selection": lambda config: self._hybrid_selection_with_existing(config, data), + "entropy_selection": lambda config: self._entropy_selection_with_existing(config, data), + "graph_selection": lambda config: self._graph_selection_with_existing(config, data), + } + base_tools.update(selection_tools) + + return base_tools + + + def _call_existing_distribution_analysis(self, data: Dict) -> str: + """Call existing data distribution analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_distribution(X, Y) + return self._format_analysis_result("Data Distribution Analysis", result) + else: + return "Insufficient data for distribution analysis" + + except Exception as e: + return f"Error in distribution analysis: {str(e)}" + + def _call_existing_structure_analysis(self, data: Dict) -> str: + """Call existing data structure analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Use default configuration or retrieve configuration from data + config = { + "n_clusters": 5, + "correlation_threshold": 0.5, + "n_neighbors": 20, + "perplexity": 30 + } + + result = inspect_data_structure(X, Y, config) + return self._format_analysis_result("Data Structure Analysis", result) + else: + return "Insufficient data for structure analysis" + + except Exception as e: + return f"Error in structure analysis: {str(e)}" + + def _evaluate_parameter_ranges(self, data: Dict) -> str: + """Evaluation Parameter Range Tool - Implementation""" + constraints_info = "Parameter Constraints Evaluation:\n" + + # Analyze the current usage of parameters + param_usage = {} + for run in data.get('log_data', {}).get('runs', []): + if run.get('parameters'): + for param, value in run['parameters'].items(): + if param not in param_usage: + param_usage[param] = [] + param_usage[param].append(float(value)) + + for param, info in self.param_constraints.items(): + min_val, max_val = info['range'] + param_type = info['type'] + + constraints_info += f"\n- {param} ({param_type}): range [{min_val}, {max_val}]" + + if param in param_usage: + values = param_usage[param] + used_min = min(values) + used_max = max(values) + constraints_info += f"\n Currently used: [{used_min:.2f}, {used_max:.2f}]" + + # Check if the parameter space has been fully explored + range_used = (used_max - used_min) / (max_val - min_val) + if range_used < 0.5: + constraints_info += f" (Only {range_used*100:.1f}% of range explored)" + + return constraints_info + + def _check_constraints_compliance(self, data: Dict) -> str: + """Check Constraint Compliance Tool - Implementation""" + violations = [] + constraint_checks = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and run.get('parameters'): + params = run['parameters'] + + # Check the basic scope constraints + for param, value in params.items(): + if param in self.param_constraints: + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + if value < min_val or value > max_val: + violations.append(f"{param}={value} not in [{min_val}, {max_val}]") + + # Check domain constraints + if not self._validate_domain_constraints(params): + violations.append(f"Domain constraints violated for run with params: {params}") + + if violations: + constraint_checks.append(f"Constraint violations found in {len(violations)} cases:") + constraint_checks.extend(violations[:5]) # Only display the first 5 + else: + constraint_checks.append("All parameters comply with constraints") + + # Check the effectiveness of parameter combinations + successful_count = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('success') and run.get('parameters')) + total_with_params = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('parameters')) + + if total_with_params > 0: + success_rate = successful_count / total_with_params * 100 + constraint_checks.append(f"\nParameter success rate: {success_rate:.1f}%") + + return "\n".join(constraint_checks) + + def _suggest_improvements(self, stage: str, data: Dict) -> str: + """Provide improvement suggestions based on stages - implementation""" + suggestions = [] + + if stage == 'inspect': + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + total_runs = data.get('log_data', {}).get('summary', {}).get('total_runs', 0) + + suggestions.append(f"Inspection Suggestions for {successful_runs}/{total_runs} successful runs:") + + if successful_runs < total_runs * 0.3: + suggestions.append("- Focus on identifying why runs are failing") + suggestions.append("- Check for common parameter ranges in failed runs") + else: + suggestions.append("- Analyze correlations between parameters and objectives") + suggestions.append("- Identify optimal parameter ranges from successful runs") + + elif stage == 'model': + suggestions.append("Modeling Suggestions:") + suggestions.append("- Use surrogate models for early prediction of results") + suggestions.append("- Balance exploration (trying new regions) and exploitation (refining good regions)") + + # Suggest modeling methods based on data volume + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + if successful_runs < 10: + suggestions.append("- With limited data, use simpler models and focus on exploration") + else: + suggestions.append("- With sufficient data, use more complex models and balance exploration/exploitation") + + elif stage == 'agglomerate': + suggestions.append("Parameter Generation Suggestions:") + suggestions.append("- Generate diverse parameter sets to explore different regions") + suggestions.append("- Focus on promising parameter ranges identified in previous stages") + suggestions.append("- Ensure all generated parameters satisfy domain constraints") + + # Suggest strategies based on goals + if self.objective == 'ECP': + suggestions.append("- For ECP, prioritize timing-critical parameters like clk_period and cell padding") + elif self.objective == 'DWL': + suggestions.append("- For DWL, focus on placement and routing parameters") + + return "\n".join(suggestions) + + def _extract_XY_from_data(self, data: Dict) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]: + """Extracting X and Y arrays from data - Reusing logic in analyze_stetrics""" + feature_vectors = [] + objective_values = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and 'metrics' in run: + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + # Use real values, if not available, use proxy values + objective_values.append(obj_values['value'] if obj_values['value'] is not None else obj_values['surrogate']) + + if feature_vectors and objective_values: + return np.array(feature_vectors), np.array(objective_values) + else: + return None, None + + def _format_analysis_result(self, title: str, result: Dict) -> str: + """Format the analysis result as a readable string""" + formatted = f"=== {title} ===\n" + + for key, value in result.items(): + if key == "model_recommendations": + formatted += "\n--- Model Recommendations ---\n" + for rec_key, rec_value in value.items(): + formatted += f"{rec_key}: {rec_value}\n" + elif isinstance(value, (int, float)): + formatted += f"{key}: {value:.4f}\n" + elif isinstance(value, list) and len(value) > 0 and isinstance(value[0], (int, float)): + # Format numerical list + formatted += f"{key}: [{', '.join(f'{v:.4f}' for v in value[:5])}{'...' if len(value) > 5 else ''}]\n" + else: + formatted += f"{key}: {value}\n" + + return formatted + + def _configure_inspection_with_existing(self, config: Dict, data: Dict) -> str: + """Use existing function configuration to check parameters""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Using configuration to run structural analysis + result = inspect_data_structure(X, Y, config) + + response = f"Inspection configured with: {config}\n" + response += "Key findings:\n" + + # Extract key findings + if "linearity_score" in result: + response += f"- Linearity: {result['linearity_score']:.3f}\n" + if "is_nonlinear" in result: + response += f"- Nonlinear: {result['is_nonlinear']}\n" + if "needs_local_models" in result: + response += f"- Needs local models: {result['needs_local_models']}\n" + if "cluster_sizes" in result: + response += f"- Cluster sizes: {result['cluster_sizes']}\n" + + return response + else: + return "No data available for inspection configuration" + + except Exception as e: + return f"Error in inspection configuration: {str(e)}" + + def _analyze_correlations_with_existing(self, params: Dict, data: Dict) -> str: + """Analyze correlation using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain relevant information + config = {"correlation_threshold": params.get('threshold', 0.5)} + result = inspect_data_structure(X, Y, config) + + response = "Feature Correlations Analysis:\n" + + if "feature_importance" in result: + response += "Feature importance (correlation with objective):\n" + for i, importance in enumerate(result["feature_importance"]): + response += f"- {self.parameter_names[i]}: {importance:.3f}\n" + + if "has_correlated_features" in result: + response += f"Has highly correlated features: {result['has_correlated_features']}\n" + if "high_correlation_pairs" in result: + response += f"High correlation pairs: {result['high_correlation_pairs']}\n" + + return response + else: + return "No data available for correlation analysis" + + except Exception as e: + return f"Error in correlation analysis: {str(e)}" + + def _cluster_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Cluster analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain clustering information + result = inspect_data_structure(X, Y, config) + + response = "Cluster Analysis:\n" + + if "cluster_sizes" in result: + response += f"Cluster sizes: {result['cluster_sizes']}\n" + if "cluster_balance" in result: + response += f"Cluster balance: {result['cluster_balance']:.3f}\n" + if "cluster_y_means" in result: + response += "Cluster objective means:\n" + for i, mean in enumerate(result["cluster_y_means"]): + response += f"- Cluster {i}: {mean:.4f}\n" + if "needs_local_models" in result: + response += f"Recommend local models: {result['needs_local_models']}\n" + + return response + else: + return "No data available for cluster analysis" + + except Exception as e: + return f"Error in cluster analysis: {str(e)}" + + def _manifold_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Perform manifold analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_manifold_structure(X, config) + return self._format_analysis_result("Manifold Structure Analysis", result) + else: + return "No data available for manifold analysis" + + except Exception as e: + return f"Error in manifold analysis: {str(e)}" + + def _local_structure_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for local structure analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_local_structure(X, config) + return self._format_analysis_result("Local Structure Analysis", result) + else: + return "No data available for local structure analysis" + + except Exception as e: + return f"Error in local structure analysis: {str(e)}" + + def _get_model_recommendations_from_existing(self, data: Dict) -> str: + """Obtain model recommendations from existing analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_structure(X, Y) + + if "model_recommendations" in result: + recommendations = result["model_recommendations"] + response = "Model Recommendations from Data Analysis:\n" + + for key, value in recommendations.items(): + if key == "feature_weights" and isinstance(value, list): + response += f"{key}: [" + response += ", ".join(f"{w:.3f}" for w in value[:5]) + if len(value) > 5: + response += ", ..." + response += "]\n" + else: + response += f"{key}: {value}\n" + + return response + else: + return "No model recommendations available" + else: + return "No data available for model recommendations" + + except Exception as e: + return f"Error getting model recommendations: {str(e)}" + + + def _configure_model_with_existing(self, config: Dict, data: Dict) -> str: + """Configure the model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Create a model using configuration + kernel_type = config.get('kernel_type', 'matern') + preprocessing = config.get('preprocessing', 'standard') + acquisition = config.get('acquisition', 'ei') + + # Create Preprocessor + preprocessor = create_preprocessor(preprocessing) + + # Create acquisition function + acq_function = create_acquisition_function(acquisition) + + response = f"Model configured successfully:\n" + response += f"- Kernel type: {kernel_type}\n" + response += f"- Preprocessing: {preprocessing}\n" + response += f"- Acquisition function: {acquisition}\n" + response += f"- Data shape: {X.shape}\n" + + # If the amount of data is sufficient, a model can be created for testing + if len(X) >= 2: + model = create_model(X, Y, kernel_type=kernel_type) + response += f"- Model created successfully with {len(X)} samples\n" + else: + response += f"- Insufficient data for model creation (need at least 2 samples, have {len(X)})\n" + + return response + else: + return "No data available for model configuration" + + except Exception as e: + return f"Error in model configuration: {str(e)}" + + def _evaluate_surrogate_with_existing(self, params: Dict, data: Dict) -> str: + """Evaluate the proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Extract proxy values (if any) + surrogate_values = None + if 'surrogates' in data.get('metrics', {}): + surrogate_values = np.array(data['metrics']['surrogates']) + + # Use existing functions to process proxy data + if surrogate_values is not None: + X_processed, y_combined, uncertainty = handle_surrogate_data(X, Y, surrogate_values) + + response = "Surrogate Model Evaluation:\n" + response += f"- Original data points: {len(Y)}\n" + response += f"- Valid target values: {np.sum(~np.isnan(Y))}\n" + response += f"- Surrogate values used: {np.sum(np.isnan(Y))}\n" + response += f"- Combined data points: {len(y_combined)}\n" + + if len(uncertainty) > 0: + response += f"- Average surrogate uncertainty: {np.mean(uncertainty):.4f}\n" + + return response + else: + return "No surrogate data available for evaluation" + else: + return "No data available for surrogate evaluation" + + except Exception as e: + return f"Error in surrogate evaluation: {str(e)}" + + def _select_acquisition_with_existing(self, method: str, data: Dict) -> str: + """Use existing functions to select collection functions""" + try: + # Create a collection function using an existing function + acq_function = create_acquisition_function(method) + + response = f"Acquisition function selected: {method.upper()}\n" + + # Provide explanations for different collection functions + explanations = { + 'ei': "Expected Improvement - balances improvement probability and magnitude", + 'ucb': "Upper Confidence Bound - favors exploration of uncertain regions", + 'pi': "Probability of Improvement - focuses on areas likely to improve", + 'augmented_ei': "Augmented EI - combines EI with exploration bonus" + } + + response += f"Explanation: {explanations.get(method, 'No explanation available')}\n" + + # Provide recommendations based on data characteristics + X, Y = self._extract_XY_from_data(data) + if X is not None and Y is not None: + if len(Y) < 10: + response += "Recommendation: With limited data, consider using UCB for better exploration\n" + else: + response += "Recommendation: With sufficient data, EI or Augmented EI are good choices\n" + + return response + + except Exception as e: + return f"Error in acquisition function selection: {str(e)}" + + def _create_surrogate_model_with_existing(self, config: Dict, data: Dict) -> str: + """Create a proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + kernel_type = config.get('kernel_type', 'matern') + noise_level = config.get('noise_level', 1e-6) + + # Create a model using existing functions + model = create_model(X, Y, noise_level=noise_level, kernel_type=kernel_type) + + response = f"Surrogate Model Created:\n" + response += f"- Kernel: {kernel_type}\n" + response += f"- Data points: {len(X)}\n" + response += f"- Features: {X.shape[1]}\n" + response += f"- Kernel parameters: {model.kernel_}\n" + + # Test model prediction + if len(X) > 0: + predictions, stds = predict_with_model(model, X[:1]) # Test a point + response += f"- Test prediction successful\n" + response += f"- Prediction range: [{predictions[0]:.4f} ± {stds[0]:.4f}]\n" + + return response + else: + return "No data available for model creation" + + except Exception as e: + return f"Error in surrogate model creation: {str(e)}" + + def _evaluate_timing_model_with_existing(self, data: Dict) -> str: + """Evaluate timing models using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate timing models using existing functions + results = evaluate_timing_model(context) + + response = "Timing Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in timing model evaluation: {str(e)}" + + def _evaluate_wirelength_model_with_existing(self, data: Dict) -> str: + """Evaluate the wire length model using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate the wire length model using existing functions + results = evaluate_wirelength_model(context) + + response = "Wirelength Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in wirelength model evaluation: {str(e)}" + + def _generate_parameters_with_existing(self, count: int, data: Dict) -> str: + """Generate parameters using existing functions""" + try: + if count <= 0 or count > 50: + return "Error: count must be between 1 and 50" + + # Obtain parameter dimensions + n_dims = len(self.parameter_names) + + # Use existing Latin hypercube sampling + samples = latin_hypercube(count, n_dims) + + response = f"Parameter Generation using Latin Hypercube:\n" + response += f"- Samples generated: {count}\n" + response += f"- Parameter dimensions: {n_dims}\n" + response += f"- Sampling method: Latin Hypercube\n" + + # Display parameter range information + response += "\nParameter Ranges:\n" + for i, param in enumerate(self.parameter_names): + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + response += f"- {param}: [{min_val}, {max_val}] ({constraint['type']})\n" + + return response + + except Exception as e: + return f"Error in parameter generation: {str(e)}" + + def _latin_hypercube_sampling_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for Latin hypercube sampling""" + try: + n_points = config.get('n_points', 10) + n_dims = len(self.parameter_names) + + # Use the existing Latin hypercube sampling function + samples = latin_hypercube(n_points, n_dims) + + response = f"Latin Hypercube Sampling:\n" + response += f"- Points: {n_points}\n" + response += f"- Dimensions: {n_dims}\n" + response += f"- Sample shape: {samples.shape}\n" + + # Display sampling statistics + response += f"- Sample range: [{samples.min():.3f}, {samples.max():.3f}]\n" + response += f"- Sample mean: {samples.mean():.3f}\n" + response += f"- Sample std: {samples.std():.3f}\n" + + return response + + except Exception as e: + return f"Error in Latin hypercube sampling: {str(e)}" + + def _configure_selection_with_existing(self, config: Dict, data: Dict) -> str: + """Configure selection strategy using existing functions""" + try: + method = config.get('method', 'hybrid') + quality_weight = config.get('quality_weight', 0.7) + uncertainty_bonus = config.get('uncertainty_bonus', 0.2) + n_points = config.get('n_points', 10) + + response = f"Selection Strategy Configured:\n" + response += f"- Method: {method}\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Uncertainty bonus: {uncertainty_bonus}\n" + response += f"- Points to select: {n_points}\n" + + # Provide explanations for different methods + method_descriptions = { + "kmeans": "K-means clustering - selects best point from each cluster", + "hybrid": "Hybrid approach - balances quality and diversity", + "entropy": "Entropy-based - maximizes information diversity", + "graph": "Graph-based - uses network centrality measures" + } + + response += f"Method description: {method_descriptions.get(method, 'No description')}\n" + + return response + + except Exception as e: + return f"Error in selection configuration: {str(e)}" + + + def _create_quality_scores_with_existing(self, config: Dict, data: Dict) -> str: + """Create a quality score using an existing function""" + try: + # Extract necessary information from data + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Simulation model predictions and uncertainties (in practical use, these should come from real models) + model_predictions = Y # Using real values as a proxy for prediction + model_uncertainties = np.ones_like(Y) * 0.1 # Simulate uncertainty + + # Create a quality score using an existing function + quality_scores = create_quality_scores(X, Y, model_predictions, model_uncertainties) + + response = "Quality Scores Created:\n" + response += f"- Data points: {len(X)}\n" + response += f"- Quality score range: [{quality_scores.min():.4f}, {quality_scores.max():.4f}]\n" + response += f"- Quality score mean: {quality_scores.mean():.4f}\n" + response += f"- Quality score std: {quality_scores.std():.4f}\n" + + response += f"- First 5 quality scores: {quality_scores[:5].tolist()}\n" + + if 'selection_data' not in data: + data['selection_data'] = {} + data['selection_data']['quality_scores'] = quality_scores + data['selection_data']['X'] = X + data['selection_data']['Y'] = Y + + return response + else: + return "No data available for quality score creation" + + except Exception as e: + return f"Error in quality score creation: {str(e)}" + + def _select_points_with_existing(self, config: Dict, data: Dict) -> str: + """_select_points_with_existing""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + method = config.get('method', 'hybrid') + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + selection_config = { + "quality_weight": quality_weight, + "uncertainty_bonus": config.get('uncertainty_bonus', 0.2) + } + + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points, + config=selection_config + ) + + response = f"Points Selected using {method.upper()} method:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Selected quality scores: {selected_qualities.tolist()}\n" + response += f"- Average quality of selected: {selected_qualities.mean():.4f}\n" + + # store selection data + data['selection_data']['selected_indices'] = selected_indices + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in point selection: {str(e)}" + + def _compare_selection_methods_with_existing(self, config: Dict, data: Dict) -> str: + """compare selection methods with existing(""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 5) + methods = ['kmeans', 'hybrid', 'entropy', 'graph'] + + response = "Selection Method Comparison:\n" + response += f"- Comparing {len(methods)} methods\n" + response += f"- Points to select: {n_points}\n\n" + + for method in methods: + try: + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points + ) + + selected_qualities = quality_scores[selected_indices] + + response += f"**{method.upper()}**:\n" + response += f" - Selected indices: {selected_indices.tolist()}\n" + response += f" - Avg quality: {selected_qualities.mean():.4f}\n" + response += f" - Quality range: [{selected_qualities.min():.4f}, {selected_qualities.max():.4f}]\n" + + except Exception as e: + response += f"**{method.upper()}**: Error - {str(e)}\n" + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in method comparison: {str(e)}" + + def _kmeans_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using K-means selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using K-means selecting function + selected_indices = kmeans_select(X, quality_scores, n_points) + + response = "K-means Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + response += f"- Quality diversity: {selected_qualities.std():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'kmeans' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in K-means selection: {str(e)}" + + def _hybrid_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing hybrid selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + distance_matrix = cdist(X, X) + + # using hybrid_select function + selected_indices = hybrid_select( + X, quality_scores, distance_matrix, + n_points, quality_weight + ) + + response = "Hybrid Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + selected_points = X[selected_indices] + min_distances = np.min(cdist(selected_points, selected_points) + np.eye(len(selected_points)) * 1e6, axis=1) + response += f"- Minimum inter-point distance: {min_distances.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'hybrid' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in hybrid selection: {str(e)}" + + def _entropy_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing entropy selecting methods""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using entropy selecting function + selected_indices = entropy_select(X, quality_scores, n_points) + + response = "Entropy-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'entropy' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in entropy selection: {str(e)}" + + def _graph_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing graph selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using graph selecting function + selected_indices = graph_select(X, quality_scores, n_points) + + response = "Graph-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'graph' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in graph selection: {str(e)}" + + + def _validate_parameters_tool(self, params: Dict) -> str: + validation_results = [] + + for param_name, value in params.items(): + if param_name in self.param_constraints: + constraint = self.param_constraints[param_name] + min_val, max_val = constraint['range'] + param_type = constraint['type'] + + if value < min_val or value > max_val: + validation_results.append(f" {param_name}={value} outside range [{min_val}, {max_val}]") + else: + validation_results.append(f" {param_name}={value} within valid range") + + if self._validate_domain_constraints(params): + validation_results.append("Domain constraints satisfied") + else: + validation_results.append("Domain constraints violated") + + return "Parameter Validation:\n" + "\n".join(validation_results) + + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + tool_instructions = { + 'inspect': ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ), + + 'agglomerate': ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + f"{constraints_text}\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + } + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** + + {stage_contexts.get(stage, '')} + + {tool_instructions.get(stage, '')} + + **Important: Use only tool calls and do not generate text replies!** + """ + + # ========= Splicing RAG ========= + rag_context = "" + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + + # Step 1: Extract error information + error_summary = "" + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + if all_errors: + # Retrieve the most recent or frequent errors + top_errors = all_errors[-3:] # Last 3 posts + error_summary = "\n".join(top_errors) + print(f"[DEBUG] Detected {len(all_errors)} error messages. Sample:\n{error_summary}") + + # Step 2: Construct RAG query + if error_summary: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"The recent optimization runs failed with errors:\n{error_summary}\n\n" + "Retrieve relevant OpenROAD documentation, known failure modes, and " + "potential parameter tuning suggestions that may fix these issues." + ) + else: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + + # Step 3: Execute search + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict, + ) + + if isinstance(rag_context, dict): # If returning dict + print(f"[DEBUG] RAG Retrieved {len(rag_context.get('docs', []))} related entries.") + for doc in rag_context.get("docs", [])[:3]: + print(f" ↳ {doc['title']} (score={doc['score']:.3f}) from {doc['source']}") + retrieved_text = rag_context.get("content", "") + else: + retrieved_text = rag_context + + # Step 4: add to prompt + if retrieved_text.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{retrieved_text}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + + if all_errors: + error_summary = "\n".join(all_errors[-5:]) # The last 5 errors + prompt += f""" + + ### Detected Run Errors + {error_summary} + + The model must now act as an **EDA Debugging Assistant**. + Using the retrieved documentation and knowledge, analyze the errors above and: + 1. Identify the root causes of each error (e.g., tool misconfiguration, parameter overflow, timing issues, etc.) + 2. Suggest **specific parameter changes or flow adjustments** to prevent these errors. + 3. Indicate whether the error is likely due to constraints, routing congestion, or timing margin. + 4. Provide a short explanation for each suggestion. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + + """ + print("[DEBUG] Added error-fix section to prompt.") + def _collect_recent_errors(self, data: Dict[str, Any], max_errors=5) -> str: + errors = [] + for run in data.get("log_data", {}).get("runs", []): + if run.get("errors"): + errors.extend(run["errors"]) + print(f"[DEBUG] Found total {len(errors)} errors in all runs.") + return "\n".join(errors[-max_errors:]) if errors else "No errors detected." + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + # """Call Claude to get recommendations for optimization parameters""" + # print(f"\n=== Calling LLM for {stage} stage ===") + """Call LLM to get recommendations for optimization parameters using react framework""" + print(f"\n=== Calling LLM with ReAct framework for {stage} stage ===") + + try: + react_prompt = self._generate_react_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(react_prompt) + print("========================") + available_tools = self._create_react_tools(stage, data) + + react_result = self.react_framework.run_react_cycle( + initial_prompt=react_prompt, + available_tools=available_tools, + max_steps=3, + temperature=0.1 + ) + # === If an error occurs, enter Debug mode === + if "log_data" in data and any(run.get("errors") for run in data["log_data"].get("runs", [])): + print("\n[DEBUG] Detected errors in previous runs. Invoking Debug Assistant mode...") + + # Collect error information + all_errors = [] + for run in data["log_data"]["runs"]: + if run.get("errors"): + all_errors.extend(run["errors"]) + error_text = "\n".join(all_errors[-5:]) # Recent entries + + # Construct a Debug Prompt + debug_prompt = f""" + You are now an **EDA Debugging Expert**. + Based on the following OpenROAD errors and RAG documentation, analyze and provide concrete repair suggestions. + + Errors Detected: + {error_text} + + Please identify: + 1. Root cause of each error. + 2. Specific parameter changes (e.g., in floorplan, CTS, or routing stages) that could fix the issue. + 3. Whether this issue is due to timing, congestion, or setup misconfiguration. + 4. One short explanation per fix. + + Return your answer in **JSON format** like: + {{ + "error_analysis": [ + {{ + "error": "...", + "cause": "...", + "fix": "...", + "params_to_adjust": {{"param_name": "new_value"}} + }} + ] + }} + """ + + # Call LLM to output repair suggestions + debug_result = self.react_framework.run_react_cycle( + initial_prompt=debug_prompt, + available_tools=available_tools, + max_steps=1, + temperature=0.2 + ) + + print("\n[DEBUG] LLM Debug Assistant Result:") + print(debug_result.get("final_answer", "")) + + # Save repair suggestions to the main results + react_result["error_fix_suggestions"] = debug_result.get("final_answer", "") + # Write files for manual viewing + with open("logs/error_fix_suggestions.json", "w") as f: + f.write(debug_result.get("final_answer", "")) + print(f"\n=== ReAct Cycle Completed ===") + print(f"Completed steps: {react_result.get('completed_steps', 0)}/{react_result.get('max_steps', 8)}") + print(f"Final Answer: {react_result['final_answer']}") + + configs = self._parse_react_final_answer(react_result["final_answer"], stage) + + if react_result.get('reasoning_history'): + print(f"\n=== Reasoning History ({len(react_result['reasoning_history'])} steps) ===") + for step in react_result['reasoning_history']: + print(f"Step {step['step']}: {step.get('thought', 'No thought')}") + + print(f"Returning config for stage '{stage}': {configs}") + return configs + + except Exception as e: + print(f"Error in LLM call for stage {stage}: {e}") + default_config = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'agglomerate': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + return default_config.get(stage, {}) + + + def _generate_react_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """generate prompts of ReAct framework""" + + stage_descriptions = { + 'inspect': ( + "You are an expert EDA optimization analyst. Analyze the optimization run data to identify patterns " + "and insights. Use the available tools to examine data distributions, correlations, and successful " + "parameter ranges. Your goal is to understand what makes runs successful and provide recommendations " + "for the modeling stage." + ), + 'model': ( + "You are an expert machine learning engineer for EDA optimization. Based on the inspection results, " + "configure the modeling approach for Bayesian optimization. Consider kernel selection, acquisition " + "functions, and surrogate modeling strategies. Balance exploration and exploitation based on the data." + ), + 'agglomerate': ( + "You are an expert parameter optimization specialist. Generate new parameter combinations for the " + "next optimization iteration. Use insights from previous stages to focus on promising regions while " + "maintaining diversity. Ensure all parameters satisfy the domain constraints." + ) + } + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + constraints_text += f"- {param} ({info['type']}, range: {info['range']})\n" + + react_format_instructions = """ +**ReAct Framework Instructions - MUST FOLLOW THIS FORMAT:** + +1. **Thought**: Analyze the current situation and decide what to do next +2. **Action**: Choose one tool from the available tools +3. **Action Input**: Provide the appropriate input for the chosen tool +4. **Observation**: Wait for the tool's response, then continue reasoning + +**Available Tools**: You have access to various analysis tools. Use them to gather information before making decisions. + +**DO NOT include Final Answer until you have completed all necessary analysis.** +**DO NOT predict or simulate tool observations.** +**You will receive actual Observation from tools before continuing.** + +Only after proper analysis: +**Final Answer Format**: Only when you have completed your analysis, provide: +Final Answer: {your_configuration_here} + +**Example**: +Thought: I need to understand the data patterns first. Let me analyze the success rates. +Action: analyze_data_patterns +Action Input: {} +Observation: [Tool response...] +Thought: Now I need to check parameter correlations... +Action: analyze_correlations +Action Input: {} +Observation: [Tool response...] +Final Answer: {"n_clusters": 5, "correlation_threshold": 0.7} +""" + + prompt = f""" + {stage_descriptions[stage]} + + **Current Stage**: {stage.upper()} + **Objective**: {self.objective} + **Platform**: {self.platform} + **Design**: {self.design} + + **Available Data**: + - Total runs: {data.get('log_data', {}).get('summary', {}).get('total_runs', 0)} + - Successful runs: {data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)} + - Failed runs: {data.get('log_data', {}).get('summary', {}).get('failed_runs', 0)} + + {constraints_text} + {react_format_instructions} + + Begin your analysis: + """ + + rag_context = "" + # ======== extract errors ======== + error_summary = self._collect_recent_errors(data) + if error_summary and "No errors" not in error_summary: + print("[DEBUG] RAG: Detected error summary, adding error analysis prompt...") + prompt += f""" + + ### Detected Run Errors + {error_summary} + + You are now acting as an **EDA Debugging Assistant**. + Analyze the errors above and: + 1. Identify the root causes. + 2. Suggest specific parameter changes. + 3. Indicate whether the error is due to timing, routing, or constraints. + 4. Provide short explanations for each. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + """ + else: + print("[DEBUG] No errors found in logs for this stage.") + if getattr(self, "supervision_feedback", ""): + prompt += f""" + + ### Supervisor Feedback + {self.supervision_feedback} + + Please prioritize these supervisor notes when making decisions in this stage. + """ + print("[SUPERVISOR][DEBUG] Added supervisor feedback into prompt.") + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict + ) + print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + if rag_context.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{rag_context}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + return prompt + + def _parse_react_final_answer(self, final_answer: str, stage: str) -> Dict[str, Any]: + """parse react final answer""" + + default_configs = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'selection': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + + configs = {} + + if final_answer and "Reached maximum steps" not in final_answer: + try: + json_match = re.search(r'\{.*\}', final_answer, re.DOTALL) + if json_match: + extracted_config = json.loads(json_match.group()) + configs[stage] = extracted_config + print(f"✓ Extracted configuration from ReAct response: {extracted_config}") + else: + configs[stage] = default_configs.get(stage, {}) + print(f"Using default configuration for {stage} stage") + except Exception as e: + print(f"Error parsing ReAct final answer: {e}") + configs[stage] = default_configs.get(stage, {}) + else: + configs[stage] = default_configs.get(stage, {}) + print(f"ReAct failed to produce answer, using default for {stage}") + + return configs + + def run_iteration(self, num_runs: int) -> Dict[str, Any]: + """Run a single inspect-optimize-agglomerate flow and return its summary.""" + return self._execute_inspect_optimize_flow(num_runs, flow_index=0) + + def run_dual_supervised_iterations(self, num_runs: int, num_flows: int) -> None: + """ + Run multiple inspect-optimize-agglomerate flows with supervisor feedback injected + into the next flow's prompt. + """ + if num_flows <= 0: + print("[WARN] num_flows must be >= 1, skipping execution.") + return + + self.supervision_feedback = "" + for flow_index in range(num_flows): + print(f"\n=== Dual-Supervised Flow {flow_index + 1}/{num_flows} ===") + flow_summary = self._execute_inspect_optimize_flow(num_runs, flow_index=flow_index) + supervisor_feedback = self._run_supervisor_review(flow_summary, flow_index) + if supervisor_feedback: + self.supervision_feedback = supervisor_feedback + print("[SUPERVISOR] Stored feedback for the next flow iteration.") + else: + print("[SUPERVISOR] Supervisor produced no feedback; continuing without updates.") + + def _execute_inspect_optimize_flow(self, num_runs: int, flow_index: int = 0) -> Dict[str, Any]: + """Internal helper containing the original inspect-optimize-agglomerate flow.""" + print(f"\n=== Starting optimization iteration #{flow_index + 1} for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations with ReAct framework for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + inspection_config = inspect_configs.get('inspect', {}) + print(f"React inspection config: {inspection_config}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics ...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspection_config.get('n_clusters', 5), + correlation_threshold=inspection_config.get('correlation_threshold', 0.5) + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + model_config = model_configs.get('model', {}) + print(f"LLM model config: {model_config}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + model_config.get('kernel_type', 'matern'), + preprocessing=model_config.get('preprocessing', 'robust'), + acquisition=model_config.get('acquisition', 'ei'), + surrogate_weight=model_config.get('surrogate_weight', 0.8) + ) + + # Get LLM recommendations for parameter selection based on all previous results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + selection_config = selection_configs.get('agglomerate', {}) + print(f"LLM selection config: {selection_config}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_config.get('method', 'hybrid'), + quality_weight=selection_config.get('quality_weight', 0.7), + uncertainty_bonus=selection_config.get('uncertainty_bonus', 0.2) + ) + + flow_summary = { + "flow_index": flow_index, + "log_data": log_data, + "metrics": metrics, + "model_results": model_results, + "inspection_config": inspection_config, + "model_config": model_config, + "selection_config": selection_config, + "num_runs": num_runs, + "recent_errors": self._collect_recent_errors({"log_data": log_data}) + } + return flow_summary + + def _run_supervisor_review(self, flow_summary: Dict[str, Any], flow_index: int) -> str: + """ + Use a secondary model to critique the previous flow and return feedback + for the next prompt. + """ + flow_snapshot = { + "log_summary": flow_summary.get("log_data", {}).get("summary", {}), + "inspection_config": flow_summary.get("inspection_config", {}), + "model_config": flow_summary.get("model_config", {}), + "selection_config": flow_summary.get("selection_config", {}), + "recent_errors": flow_summary.get("recent_errors", ""), + "objective": self.objective, + "platform": self.platform, + "design": self.design, + } + + supervisor_prompt = ( + "You are the supervisor model for an EDA optimization agent.\n" + "The primary agent just finished an inspect-optimize-agglomerate flow.\n" + "Provide concise feedback (<=300 words) to guide the next flow. " + "Focus on:\n" + "1) What to adjust in inspection/model/selection configs,\n" + "2) Specific parameter or constraint reminders,\n" + "3) Warnings about errors or data issues.\n" + "Return plain text; start the message with 'Supervisor Feedback:'.\n" + f"Flow #{flow_index + 1} summary (JSON):\n{json.dumps(flow_snapshot, ensure_ascii=False, indent=2)}" + ) + print(f"[SUPERVISOR] Supervisor prompt: {supervisor_prompt}") + + try: + response = self.supervisor_client.chat.completions.create( + model=self.supervisor_model_name, + messages=[ + { + "role": "system", + "content": "You are a senior EDA optimization reviewer. Be concise and actionable.", + }, + {"role": "user", "content": supervisor_prompt}, + ], + temperature=0.2, + max_tokens=2048, + ) + feedback = response.choices[0].message.content.strip() + print(f"[SUPERVISOR] Feedback generated (len={len(feedback)}).") + return feedback + except Exception as e: + print(f"[SUPERVISOR] Failed to generate feedback: {e}") + return "" + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) not in (5, 6): + print("Usage: optimize_dual.py []") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + num_flows = int(sys.argv[5]) if len(sys.argv) == 6 else 1 + + workflow = OptimizationWorkflow(platform, design, objective) + # Keep backward compatibility: a single flow behaves like the legacy run_iteration. + workflow.run_dual_supervised_iterations(num_runs, num_flows) + +if __name__ == "__main__": + main() diff --git a/flow-Agent/optimize_textgrad.py b/flow-Agent/optimize_textgrad.py new file mode 100644 index 0000000..2588209 --- /dev/null +++ b/flow-Agent/optimize_textgrad.py @@ -0,0 +1,2699 @@ +#!/usr/bin/env python3 +import json +import os +import sys +import re +import numpy as np +from typing import Dict, List, Any, Tuple, Optional +import anthropic +import csv +import random +from rag.util import answerWithRAG +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from sentence_transformers import SentenceTransformer +import torch +from pathlib import Path +from openai import OpenAI +from inspectfuncs import * +from modelfuncs import * +from agglomfuncs import * +import warnings +warnings.filterwarnings("ignore", category=RuntimeWarning) + +print("Python executable:", sys.executable) +print("sys.path:", sys.path[:3]) +print("Current working dir:", os.getcwd()) + +for pkg in ["anthropic", "sentence_transformers", "torch", "openai"]: + try: + __import__(pkg) + print(f" Imported {pkg}") + except ImportError as e: + print(f" Failed to import {pkg}: {e}") + +def process_log_file(log_path: str) -> Dict[str, Any]: + """Process a single log file to extract relevant metrics""" + run_data = { + 'file': os.path.basename(log_path), + 'success': False, + 'metrics': {}, + 'errors': [] + } + + with open(log_path, 'r') as f: + content = f.read() + print(f"File size: {len(content)} characters") + + # Extract timing information + timing_metrics = extract_timing_metrics(content) + run_data['metrics'].update(timing_metrics) + + # Extract wirelength information + wl_metrics = extract_wirelength_metrics(content) + run_data['metrics'].update(wl_metrics) + + # Extract any errors + errors = extract_errors(content) + run_data['errors'].extend(errors) + # === Inject a simulated error for testing RAG debugging === + # if "run3" in log_path: # 👈 你可以换成任意 run,比如 run1 或 run2 + # fake_error = "[ERROR] TEST_SIM: Simulated routing congestion failure" + # print(f"[DEBUG] Injected simulated error in {log_path}: {fake_error}") + # run_data['errors'].append(fake_error) + # run_data['success'] = False + + run_data['success'] = is_run_successful(content, errors) + + return run_data + +def extract_timing_metrics(log_content: str) -> Dict[str, float]: + """Extract timing-related metrics from log content""" + metrics = {} + + # Extract worst slack (final) + slack_match = re.search(r'(?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + if slack_match: + metrics['worst_slack'] = float(slack_match.group(1)) + + # Extract CTS worst slack + # cts_slack_match = re.search(r'(?:CTS|Clock Tree) (?:worst slack|WNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + cts_slack_match = re.search(r'Timing-driven:\s*(?:worst slack|WNS)\s+([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_slack_match: + metrics['cts_ws'] = float(cts_slack_match.group(1)) + + # Extract clock period + # period_match = re.search(r'[Cc]lock period:\s*([\d.]+)', log_content) + period_match = re.search(r'clock period to\s*([\d.]+)', log_content) + if period_match: + metrics['clock_period'] = float(period_match.group(1)) + + # Extract TNS + # tns_match = re.search(r'(?:Total negative slack|TNS):\s*([-\d.]+)', log_content, re.IGNORECASE) + tns_match = re.search(r'"finish__timing__setup__tns"\s*:\s*([-\d.eE]+)', log_content) + if tns_match: + metrics['tns'] = float(tns_match.group(1)) + + return metrics + +def extract_wirelength_metrics(log_content: str) -> Dict[str, float]: + """Extract wirelength-related metrics from log content""" + metrics = {} + + # Extract total wirelength + wl_match = re.search(r'Total wirelength: ([\d.]+)', log_content) + if wl_match: + metrics['total_wirelength'] = float(wl_match.group(1)) + + # Extract estimated wirelength after CTS + # cts_wl_match = re.search(r'Estimated wirelength: ([\d.]+)', log_content) + cts_wl_match = re.search(r'"?cts__route__wirelength__estimated"?\s*[:=]\s*([-\d.eE]+)', log_content, re.IGNORECASE) + if cts_wl_match: + metrics['cts_wirelength'] = float(cts_wl_match.group(1)) + + return metrics + +def extract_errors(log_content: str) -> List[str]: + """Extract error messages from log content""" + errors = [] + + # Look for common error patterns + error_patterns = [ + r'Error: .*', + r'ERROR: .*', + r'FATAL: .*', + r'Failed: .*' + ] + + for pattern in error_patterns: + matches = re.finditer(pattern, log_content, re.MULTILINE) + errors.extend(match.group(0) for match in matches) + + return errors + +def is_run_successful(log_content: str, errors: List[str], filename: str = "") -> bool: + """Determine if a run was successful based on log content and errors""" + if errors: + # If any real error lines were found, this file is a failure indicator + return False + + # Look for completion markers + completion_markers = [ + 'Flow complete', + 'Finished successfully', + 'Writing out GDS/OAS', + '6_report' + ] + + return any(marker in log_content for marker in completion_markers) + + +class ReActFramework: + """ReAct framework implementation""" + + def __init__(self, client, model_name="DeepSeek-R1"): + self.client = client + self.model_name = model_name + self.conversation_history = [] + + def add_to_history(self, role: str, content: str): + """add conversation history""" + self.conversation_history.append({"role": role, "content": content}) + + def clear_history(self): + """clear conversation history""" + self.conversation_history = [] + + def extract_thought_action(self, response: str) -> Tuple[str, str, str]: + """ + Extract Thought, Action, and Action Input from LLM responses + Format: Thought:... Action:... Action Input: ... + """ + thought = "" + action = "" + action_input = "" + + # Extract Thought + thought_match = re.search(r'Thought:\s*(.*?)(?=\nAction:|$)', response, re.DOTALL) + if thought_match: + thought = thought_match.group(1).strip() + + # Extract Action + action_match = re.search(r'Action:\s*(\w+)', response) + if action_match: + action = action_match.group(1).strip() + + # Extract Action Input + action_input_match = re.search(r'Action Input:\s*(.*?)(?=\nObservation:|$)', response, re.DOTALL) + if action_input_match: + action_input = action_input_match.group(1).strip() + # Try to parse JSON + try: + if action_input.startswith('{') or action_input.startswith('['): + action_input = json.loads(action_input) + except: + pass # Maintain the string format + + if "Final Answer:" in response and ("Action:" in response or "Observation:" in response): + + response = response.split("Final Answer:")[0] + print("Removed premature Final Answer from response") + + return thought, action, action_input + + def execute_action(self, action: str, action_input: Any, available_tools: Dict) -> str: + """Execute tool call and return observation results""" + if action in available_tools: + try: + result = available_tools[action](action_input) + return f"Action executed successfully. Result: {result}" + except Exception as e: + return f"Action execution failed: {str(e)}" + else: + return f"Unknown action: {action}. Available actions: {list(available_tools.keys())}" + + def run_react_cycle(self, + initial_prompt: str, + available_tools: Dict, + max_steps: int = 5, + temperature: float = 0.1) -> Dict[str, Any]: + """ + Run ReAct loop + + Args: + initial_prompt: Initial prompt + available_tools: Available tool function dictionary + max_steps: Maximum reasoning steps + temperature: temperature parameter + + Returns: + a dictionary containing the final result and the reasoning history + """ + self.clear_history() + self.add_to_history("user", initial_prompt) + + history = [] + final_answer = None + completed_steps = 0 + + for step in range(max_steps): + print(f"\n=== ReAct Step {step + 1}/{max_steps} ===") + completed_steps = step + 1 + + # Call LLM to obtain response + try: + response = self.client.chat.completions.create( + model=self.model_name, + messages=self.conversation_history, + temperature=temperature, + max_tokens=1024 + ) + + llm_response = response.choices[0].message.content + print(f"LLM Response: {llm_response}") + except Exception as e: + print(f"Error calling LLM: {e}") + llm_response = f"Error in LLM call: {e}" + + # Extract Thought, Action, Action Input + thought, action, action_input = self.extract_thought_action(llm_response) + + step_data = { + "step": step + 1, + "thought": thought, + "action": action, + "action_input": action_input, + "llm_response": llm_response + } + + # Check if it is the final answer + final_answer_detected = False + if "Final Answer:" in llm_response: + final_answer_match = re.search(r'Final Answer:\s*(.*?)$', llm_response, re.DOTALL) + if final_answer_match: + final_answer = final_answer_match.group(1).strip() + step_data["final_answer"] = final_answer + final_answer_detected = True + print(f"✓ Final answer detected at step {step + 1}") + + observation = "" + # Execute actions and obtain observation results + if action and not final_answer_detected: + observation = self.execute_action(action, action_input, available_tools) + step_data["observation"] = observation + + # Update conversation history + self.add_to_history("assistant", llm_response) + self.add_to_history("user", f"Observation: {observation}") + + print(f"Thought: {thought}") + print(f"Action: {action}") + print(f"Action Input: {action_input}") + print(f"Observation: {observation}") + else: + if not final_answer_detected: + # If there is no clear action, it may be during the reasoning process + self.add_to_history("assistant", llm_response) + step_data["observation"] = "No action taken - continuing reasoning" + observation = "No action taken" + else: + # If it is the final answer, no further action is required + step_data["observation"] = "Final answer provided - cycle complete" + observation = "Final answer provided" + + history.append(step_data) + + if final_answer_detected: + print(f" ReAct cycle completed at step {step + 1} with final answer") + break + + # Check if it should end early + if step >= max_steps - 1: + final_answer = f"Reached maximum steps ({max_steps}) without final answer" + print(f" Reached maximum steps without final answer") + break + + if final_answer is None: + final_answer = "No final answer produced" + + return { + "final_answer": final_answer, + "reasoning_history": history, + "success": final_answer is not None and "Reached maximum steps" not in final_answer and "No final answer" not in final_answer, + "completed_steps": completed_steps, + "max_steps": max_steps + } + + +class OptimizationWorkflow: + def __init__(self, platform: str, design: str, objective: str): + self.platform = platform + self.design = design + self.objective = objective.upper() # Convert to uppercase + + # Load configuration + self.config = self._load_config() + + # [TextGrad Integration] 1. Convert static Prompts into Optimizable State Variables + self.tool_instructions = { + 'inspect': ( + f"**Stage: Inspect**\n" + "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + "Please analyze the data and provide insights on:\n" + "1. Key patterns in successful vs unsuccessful runs.\n" + "2. Parameter ranges that appear promising.\n" + "3. Any timing or wirelength trends.\n" + "4. Recommendations for subsequent runs.\n" + "5. We hope to further reduce the total wirelength.\n" + ), + + 'model': ( + f"**Stage: Model**\n" + "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + "Please suggest:\n" + "1. Appropriate modeling techniques.\n" + "2. Key parameters to focus on.\n" + "3. Surrogate model recommendations.\n" + "4. Acquisition function choices.\n" + ), + + 'agglomerate': ( + f"**Stage: Agglomerate**\n" + "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + ) + } + + # Find the design configuration + configurations = self.config.get('configurations', []) + for config in configurations: + if ( + config['platform'].lower() == self.platform.lower() + and config['design'].lower() == self.design.lower() + and config['goal'].upper() == self.objective + ): + self.design_config = config + break + else: + raise ValueError( + f"No configuration found for platform={self.platform}, design={self.design}, objective={self.objective}" + ) + + # Define initial clock periods for each design and platform + initial_clock_periods = { + ('asap7', 'aes'): 400, # in picoseconds + ('asap7', 'ibex'): 1260, # in picoseconds + ('asap7', 'jpeg'): 1100, # in picoseconds + ('sky130hd', 'aes'): 4.5, # in nanoseconds + ('sky130hd', 'ibex'): 10.0,# in nanoseconds + ('sky130hd', 'jpeg'): 8.0, # in nanoseconds + } + + # Get the initial clock period for the current platform and design + key = (self.platform.lower(), self.design.lower()) + if key in initial_clock_periods: + self.initial_clk_period = initial_clock_periods[key] + else: + raise ValueError(f"Initial clock period not defined for platform={self.platform}, design={self.design}") + + # Calculate clock period range + min_clk = self.initial_clk_period * 0.7 + max_clk = self.initial_clk_period * 1.3 + + # Define parameter names in the expected order + self.parameter_names = [ + 'core_util', + 'cell_pad_global', + 'cell_pad_detail', + 'synth_flatten', + 'pin_layer', + 'above_layer', + 'tns', + 'lb_addon', + 'cts_size', + 'cts_diameter', + 'enable_dpo', + 'clk_period' + ] + + # Set all parameter constraints including clock period range + self.param_constraints = { + 'core_util': {'type': 'int', 'range': [20, 99]}, + 'cell_pad_global': {'type': 'int', 'range': [0, 4]}, + 'cell_pad_detail': {'type': 'int', 'range': [0, 4]}, + 'synth_flatten': {'type': 'int', 'range': [0, 1]}, + 'pin_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'above_layer': {'type': 'float', 'range': [0.2, 0.7]}, + 'tns': {'type': 'int', 'range': [70, 100]}, + 'lb_addon': {'type': 'float', 'range': [0.00, 0.99]}, + 'cts_size': {'type': 'int', 'range': [10, 40]}, + 'cts_diameter': {'type': 'int', 'range': [80, 120]}, + 'enable_dpo': {'type': 'int', 'range': [0, 1]}, + 'clk_period': {'type': 'float', 'range': [min_clk, max_clk]} + } + + # Load initial parameters and SDC context + self.initial_params = self._load_initial_params() + self.sdc_context = self._load_sdc_context() + + emb_np, docs, docsDict = load_embeddings_and_docs() + self.rag_embeddings = torch.tensor(emb_np).cpu() + self.rag_docs = docs + self.rag_docsDict = docsDict + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + model_path = model_path.resolve() + # self.rag_model = SentenceTransformer(str(model_path)) + self.rag_model = SentenceTransformer(str(model_path), device='cpu') + + self.react_framework = ReActFramework( + client=OpenAI( + base_url="https://ai.gitee.com/v1", + # api_key="X7NJOWYHJX7A1BDACXRLWC1ZMCUWM4FX0Q6FHJ1Q", + api_key="MZ1RSHGF7QPGC8HHBOSPBQTDAZ6QD9NBCHROSZ1B", + ), + model_name="DeepSeek-R1" + ) + # Secondary supervisor model for dual-LLM flow. All values can be overridden via env variables. + self.supervisor_client = OpenAI( + base_url=os.environ.get("SUPERVISOR_BASE_URL", "https://ai.gitee.com/v1"), + api_key=os.environ.get("SUPERVISOR_API_KEY", "MZ1RSHGF7QPGC8HHBOSPBQTDAZ6QD9NBCHROSZ1B"), + ) + self.supervisor_model_name = os.environ.get("SUPERVISOR_MODEL", "DeepSeek-R1") + self.supervision_feedback: str = "" + + def _optimize_prompt_with_textgrad(self, stage: str, feedback: str): + """ + [TextGrad Integration] Core function: Optimize Prompt(Variable) based on feedback (Gradient). + """ + print(f"\n[TextGrad] Optimizing '{stage}' instructions based on feedback...") + + current_instruction = self.tool_instructions.get(stage, "") + + # This is a meta-prompt used to make LLM act as an "optimizer". + optimizer_prompt = f""" + You are a Prompt Optimizer for an EDA Logic Synthesis Agent. + + **Current System Instruction**: + {current_instruction} + + **Critique/Gradient (Feedback from Supervisor)**: + {feedback} + + **Task**: + Rewrite the "Current System Instruction" to explicitly address the Critique. + - If the critic says the agent ignored errors, strengthen the error-handling instructions. + - If the critic says the agent explored too little, emphasize exploration in the instructions. + - Keep the format consistent, but change the content to be more effective. + + Return ONLY the new instruction text. + """ + + try: + response = self.supervisor_client.chat.completions.create( + model=self.supervisor_model_name, + messages=[{"role": "user", "content": optimizer_prompt}], + temperature=0.2 + ) + new_instruction = response.choices[0].message.content.strip() + + # Variable Update + self.tool_instructions[stage] = new_instruction + print(f"[TextGrad] Successfully updated instructions for stage '{stage}'.") + + except Exception as e: + print(f"[TextGrad] Failed to optimize prompt: {e}") + + def _create_react_tools(self, stage: str, data: Dict[str, Any]) -> Dict: + """Create available utility functions for different stages""" + + base_tools = { + "analyze_data_distribution": lambda x: self._call_existing_distribution_analysis(data), + "analyze_data_structure": lambda x: self._call_existing_structure_analysis(data), + "evaluate_parameter_ranges": lambda x: self._evaluate_parameter_ranges(data), + "check_constraints": lambda x: self._check_constraints_compliance(data), + "suggest_improvements": lambda x: self._suggest_improvements(stage, data), + } + + if stage == 'inspect': + inspection_tools = { + "configure_inspection": lambda config: self._configure_inspection_with_existing(config, data), + "analyze_correlations": lambda params: self._analyze_correlations_with_existing(params, data), + "cluster_analysis": lambda config: self._cluster_analysis_with_existing(config, data), + "manifold_analysis": lambda config: self._manifold_analysis_with_existing(config, data), + "local_structure_analysis": lambda config: self._local_structure_analysis_with_existing(config, data), + } + base_tools.update(inspection_tools) + + elif stage == 'model': + modeling_tools = { + "configure_model": lambda config: self._configure_model_with_existing(config, data), + "evaluate_surrogate": lambda params: self._evaluate_surrogate_with_existing(params, data), + "select_acquisition": lambda method: self._select_acquisition_with_existing(method, data), + "create_surrogate_model": lambda config: self._create_surrogate_model_with_existing(config, data), + "evaluate_timing_model": lambda x: self._evaluate_timing_model_with_existing(data), + "evaluate_wirelength_model": lambda x: self._evaluate_wirelength_model_with_existing(data), + "get_model_recommendations": lambda x: self._get_model_recommendations_from_existing(data), + } + base_tools.update(modeling_tools) + + elif stage == 'agglomerate': + selection_tools = { + "configure_selection": lambda config: self._configure_selection_with_existing(config, data), + "generate_parameters": lambda count: self._generate_parameters_with_existing(count, data), + "validate_parameters": lambda params: self._validate_parameters_tool(params), + "latin_hypercube_sampling": lambda config: self._latin_hypercube_sampling_with_existing(config, data), + "create_quality_scores": lambda config: self._create_quality_scores_with_existing(config, data), + "select_points": lambda config: self._select_points_with_existing(config, data), + "compare_selection_methods": lambda config: self._compare_selection_methods_with_existing(config, data), + "kmeans_selection": lambda config: self._kmeans_selection_with_existing(config, data), + "hybrid_selection": lambda config: self._hybrid_selection_with_existing(config, data), + "entropy_selection": lambda config: self._entropy_selection_with_existing(config, data), + "graph_selection": lambda config: self._graph_selection_with_existing(config, data), + } + base_tools.update(selection_tools) + + return base_tools + + + def _call_existing_distribution_analysis(self, data: Dict) -> str: + """Call existing data distribution analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_distribution(X, Y) + return self._format_analysis_result("Data Distribution Analysis", result) + else: + return "Insufficient data for distribution analysis" + + except Exception as e: + return f"Error in distribution analysis: {str(e)}" + + def _call_existing_structure_analysis(self, data: Dict) -> str: + """Call existing data structure analysis functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Use default configuration or retrieve configuration from data + config = { + "n_clusters": 5, + "correlation_threshold": 0.5, + "n_neighbors": 20, + "perplexity": 30 + } + + result = inspect_data_structure(X, Y, config) + return self._format_analysis_result("Data Structure Analysis", result) + else: + return "Insufficient data for structure analysis" + + except Exception as e: + return f"Error in structure analysis: {str(e)}" + + def _evaluate_parameter_ranges(self, data: Dict) -> str: + """Evaluation Parameter Range Tool - Implementation""" + constraints_info = "Parameter Constraints Evaluation:\n" + + # Analyze the current usage of parameters + param_usage = {} + for run in data.get('log_data', {}).get('runs', []): + if run.get('parameters'): + for param, value in run['parameters'].items(): + if param not in param_usage: + param_usage[param] = [] + param_usage[param].append(float(value)) + + for param, info in self.param_constraints.items(): + min_val, max_val = info['range'] + param_type = info['type'] + + constraints_info += f"\n- {param} ({param_type}): range [{min_val}, {max_val}]" + + if param in param_usage: + values = param_usage[param] + used_min = min(values) + used_max = max(values) + constraints_info += f"\n Currently used: [{used_min:.2f}, {used_max:.2f}]" + + # Check if the parameter space has been fully explored + range_used = (used_max - used_min) / (max_val - min_val) + if range_used < 0.5: + constraints_info += f" (Only {range_used*100:.1f}% of range explored)" + + return constraints_info + + def _check_constraints_compliance(self, data: Dict) -> str: + """Check Constraint Compliance Tool - Implementation""" + violations = [] + constraint_checks = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and run.get('parameters'): + params = run['parameters'] + + # Check the basic scope constraints + for param, value in params.items(): + if param in self.param_constraints: + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + if value < min_val or value > max_val: + violations.append(f"{param}={value} not in [{min_val}, {max_val}]") + + # Check domain constraints + if not self._validate_domain_constraints(params): + violations.append(f"Domain constraints violated for run with params: {params}") + + if violations: + constraint_checks.append(f"Constraint violations found in {len(violations)} cases:") + constraint_checks.extend(violations[:5]) # Only display the first 5 + else: + constraint_checks.append("All parameters comply with constraints") + + # Check the effectiveness of parameter combinations + successful_count = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('success') and run.get('parameters')) + total_with_params = sum(1 for run in data.get('log_data', {}).get('runs', []) + if run.get('parameters')) + + if total_with_params > 0: + success_rate = successful_count / total_with_params * 100 + constraint_checks.append(f"\nParameter success rate: {success_rate:.1f}%") + + return "\n".join(constraint_checks) + + def _suggest_improvements(self, stage: str, data: Dict) -> str: + """Provide improvement suggestions based on stages - implementation""" + suggestions = [] + + if stage == 'inspect': + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + total_runs = data.get('log_data', {}).get('summary', {}).get('total_runs', 0) + + suggestions.append(f"Inspection Suggestions for {successful_runs}/{total_runs} successful runs:") + + if successful_runs < total_runs * 0.3: + suggestions.append("- Focus on identifying why runs are failing") + suggestions.append("- Check for common parameter ranges in failed runs") + else: + suggestions.append("- Analyze correlations between parameters and objectives") + suggestions.append("- Identify optimal parameter ranges from successful runs") + + elif stage == 'model': + suggestions.append("Modeling Suggestions:") + suggestions.append("- Use surrogate models for early prediction of results") + suggestions.append("- Balance exploration (trying new regions) and exploitation (refining good regions)") + + # Suggest modeling methods based on data volume + successful_runs = data.get('log_data', {}).get('summary', {}).get('successful_runs', 0) + if successful_runs < 10: + suggestions.append("- With limited data, use simpler models and focus on exploration") + else: + suggestions.append("- With sufficient data, use more complex models and balance exploration/exploitation") + + elif stage == 'agglomerate': + suggestions.append("Parameter Generation Suggestions:") + suggestions.append("- Generate diverse parameter sets to explore different regions") + suggestions.append("- Focus on promising parameter ranges identified in previous stages") + suggestions.append("- Ensure all generated parameters satisfy domain constraints") + + # Suggest strategies based on goals + if self.objective == 'ECP': + suggestions.append("- For ECP, prioritize timing-critical parameters like clk_period and cell padding") + elif self.objective == 'DWL': + suggestions.append("- For DWL, focus on placement and routing parameters") + + return "\n".join(suggestions) + + def _extract_XY_from_data(self, data: Dict) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]: + """Extracting X and Y arrays from data - Reusing logic in analyze_stetrics""" + feature_vectors = [] + objective_values = [] + + for run in data.get('log_data', {}).get('runs', []): + if run.get('success') and 'metrics' in run: + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + # Use real values, if not available, use proxy values + objective_values.append(obj_values['value'] if obj_values['value'] is not None else obj_values['surrogate']) + + if feature_vectors and objective_values: + return np.array(feature_vectors), np.array(objective_values) + else: + return None, None + + def _format_analysis_result(self, title: str, result: Dict) -> str: + """Format the analysis result as a readable string""" + formatted = f"=== {title} ===\n" + + for key, value in result.items(): + if key == "model_recommendations": + formatted += "\n--- Model Recommendations ---\n" + for rec_key, rec_value in value.items(): + formatted += f"{rec_key}: {rec_value}\n" + elif isinstance(value, (int, float)): + formatted += f"{key}: {value:.4f}\n" + elif isinstance(value, list) and len(value) > 0 and isinstance(value[0], (int, float)): + # Format numerical list + formatted += f"{key}: [{', '.join(f'{v:.4f}' for v in value[:5])}{'...' if len(value) > 5 else ''}]\n" + else: + formatted += f"{key}: {value}\n" + + return formatted + + def _configure_inspection_with_existing(self, config: Dict, data: Dict) -> str: + """Use existing function configuration to check parameters""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Using configuration to run structural analysis + result = inspect_data_structure(X, Y, config) + + response = f"Inspection configured with: {config}\n" + response += "Key findings:\n" + + # Extract key findings + if "linearity_score" in result: + response += f"- Linearity: {result['linearity_score']:.3f}\n" + if "is_nonlinear" in result: + response += f"- Nonlinear: {result['is_nonlinear']}\n" + if "needs_local_models" in result: + response += f"- Needs local models: {result['needs_local_models']}\n" + if "cluster_sizes" in result: + response += f"- Cluster sizes: {result['cluster_sizes']}\n" + + return response + else: + return "No data available for inspection configuration" + + except Exception as e: + return f"Error in inspection configuration: {str(e)}" + + def _analyze_correlations_with_existing(self, params: Dict, data: Dict) -> str: + """Analyze correlation using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain relevant information + config = {"correlation_threshold": params.get('threshold', 0.5)} + result = inspect_data_structure(X, Y, config) + + response = "Feature Correlations Analysis:\n" + + if "feature_importance" in result: + response += "Feature importance (correlation with objective):\n" + for i, importance in enumerate(result["feature_importance"]): + response += f"- {self.parameter_names[i]}: {importance:.3f}\n" + + if "has_correlated_features" in result: + response += f"Has highly correlated features: {result['has_correlated_features']}\n" + if "high_correlation_pairs" in result: + response += f"High correlation pairs: {result['high_correlation_pairs']}\n" + + return response + else: + return "No data available for correlation analysis" + + except Exception as e: + return f"Error in correlation analysis: {str(e)}" + + def _cluster_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Cluster analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Perform structural analysis to obtain clustering information + result = inspect_data_structure(X, Y, config) + + response = "Cluster Analysis:\n" + + if "cluster_sizes" in result: + response += f"Cluster sizes: {result['cluster_sizes']}\n" + if "cluster_balance" in result: + response += f"Cluster balance: {result['cluster_balance']:.3f}\n" + if "cluster_y_means" in result: + response += "Cluster objective means:\n" + for i, mean in enumerate(result["cluster_y_means"]): + response += f"- Cluster {i}: {mean:.4f}\n" + if "needs_local_models" in result: + response += f"Recommend local models: {result['needs_local_models']}\n" + + return response + else: + return "No data available for cluster analysis" + + except Exception as e: + return f"Error in cluster analysis: {str(e)}" + + def _manifold_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Perform manifold analysis using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_manifold_structure(X, config) + return self._format_analysis_result("Manifold Structure Analysis", result) + else: + return "No data available for manifold analysis" + + except Exception as e: + return f"Error in manifold analysis: {str(e)}" + + def _local_structure_analysis_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for local structure analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None: + result = analyze_local_structure(X, config) + return self._format_analysis_result("Local Structure Analysis", result) + else: + return "No data available for local structure analysis" + + except Exception as e: + return f"Error in local structure analysis: {str(e)}" + + def _get_model_recommendations_from_existing(self, data: Dict) -> str: + """Obtain model recommendations from existing analysis""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + result = inspect_data_structure(X, Y) + + if "model_recommendations" in result: + recommendations = result["model_recommendations"] + response = "Model Recommendations from Data Analysis:\n" + + for key, value in recommendations.items(): + if key == "feature_weights" and isinstance(value, list): + response += f"{key}: [" + response += ", ".join(f"{w:.3f}" for w in value[:5]) + if len(value) > 5: + response += ", ..." + response += "]\n" + else: + response += f"{key}: {value}\n" + + return response + else: + return "No model recommendations available" + else: + return "No data available for model recommendations" + + except Exception as e: + return f"Error getting model recommendations: {str(e)}" + + + def _configure_model_with_existing(self, config: Dict, data: Dict) -> str: + """Configure the model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Create a model using configuration + kernel_type = config.get('kernel_type', 'matern') + preprocessing = config.get('preprocessing', 'standard') + acquisition = config.get('acquisition', 'ei') + + # Create Preprocessor + preprocessor = create_preprocessor(preprocessing) + + # Create acquisition function + acq_function = create_acquisition_function(acquisition) + + response = f"Model configured successfully:\n" + response += f"- Kernel type: {kernel_type}\n" + response += f"- Preprocessing: {preprocessing}\n" + response += f"- Acquisition function: {acquisition}\n" + response += f"- Data shape: {X.shape}\n" + + # If the amount of data is sufficient, a model can be created for testing + if len(X) >= 2: + model = create_model(X, Y, kernel_type=kernel_type) + response += f"- Model created successfully with {len(X)} samples\n" + else: + response += f"- Insufficient data for model creation (need at least 2 samples, have {len(X)})\n" + + return response + else: + return "No data available for model configuration" + + except Exception as e: + return f"Error in model configuration: {str(e)}" + + def _evaluate_surrogate_with_existing(self, params: Dict, data: Dict) -> str: + """Evaluate the proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Extract proxy values (if any) + surrogate_values = None + if 'surrogates' in data.get('metrics', {}): + surrogate_values = np.array(data['metrics']['surrogates']) + + # Use existing functions to process proxy data + if surrogate_values is not None: + X_processed, y_combined, uncertainty = handle_surrogate_data(X, Y, surrogate_values) + + response = "Surrogate Model Evaluation:\n" + response += f"- Original data points: {len(Y)}\n" + response += f"- Valid target values: {np.sum(~np.isnan(Y))}\n" + response += f"- Surrogate values used: {np.sum(np.isnan(Y))}\n" + response += f"- Combined data points: {len(y_combined)}\n" + + if len(uncertainty) > 0: + response += f"- Average surrogate uncertainty: {np.mean(uncertainty):.4f}\n" + + return response + else: + return "No surrogate data available for evaluation" + else: + return "No data available for surrogate evaluation" + + except Exception as e: + return f"Error in surrogate evaluation: {str(e)}" + + def _select_acquisition_with_existing(self, method: str, data: Dict) -> str: + """Use existing functions to select collection functions""" + try: + # Create a collection function using an existing function + acq_function = create_acquisition_function(method) + + response = f"Acquisition function selected: {method.upper()}\n" + + # Provide explanations for different collection functions + explanations = { + 'ei': "Expected Improvement - balances improvement probability and magnitude", + 'ucb': "Upper Confidence Bound - favors exploration of uncertain regions", + 'pi': "Probability of Improvement - focuses on areas likely to improve", + 'augmented_ei': "Augmented EI - combines EI with exploration bonus" + } + + response += f"Explanation: {explanations.get(method, 'No explanation available')}\n" + + # Provide recommendations based on data characteristics + X, Y = self._extract_XY_from_data(data) + if X is not None and Y is not None: + if len(Y) < 10: + response += "Recommendation: With limited data, consider using UCB for better exploration\n" + else: + response += "Recommendation: With sufficient data, EI or Augmented EI are good choices\n" + + return response + + except Exception as e: + return f"Error in acquisition function selection: {str(e)}" + + def _create_surrogate_model_with_existing(self, config: Dict, data: Dict) -> str: + """Create a proxy model using existing functions""" + try: + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + kernel_type = config.get('kernel_type', 'matern') + noise_level = config.get('noise_level', 1e-6) + + # Create a model using existing functions + model = create_model(X, Y, noise_level=noise_level, kernel_type=kernel_type) + + response = f"Surrogate Model Created:\n" + response += f"- Kernel: {kernel_type}\n" + response += f"- Data points: {len(X)}\n" + response += f"- Features: {X.shape[1]}\n" + response += f"- Kernel parameters: {model.kernel_}\n" + + # Test model prediction + if len(X) > 0: + predictions, stds = predict_with_model(model, X[:1]) # Test a point + response += f"- Test prediction successful\n" + response += f"- Prediction range: [{predictions[0]:.4f} ± {stds[0]:.4f}]\n" + + return response + else: + return "No data available for model creation" + + except Exception as e: + return f"Error in surrogate model creation: {str(e)}" + + def _evaluate_timing_model_with_existing(self, data: Dict) -> str: + """Evaluate timing models using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate timing models using existing functions + results = evaluate_timing_model(context) + + response = "Timing Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in timing model evaluation: {str(e)}" + + def _evaluate_wirelength_model_with_existing(self, data: Dict) -> str: + """Evaluate the wire length model using existing functions""" + try: + # Build context + context = { + 'log_data': data.get('log_data', {}), + 'metrics': data.get('metrics', {}), + 'model_recommendations': data.get('model_recommendations', {}) + } + + # Evaluate the wire length model using existing functions + results = evaluate_wirelength_model(context) + + response = "Wirelength Model Evaluation:\n" + + if 'performance' in results: + for key, value in results['performance'].items(): + response += f"- {key}: {value:.4f}\n" + + if 'suggestions' in results: + response += "\nSuggestions:\n" + for suggestion in results['suggestions']: + response += f"- {suggestion}\n" + + if 'recommendations' in results: + response += "\nRecommendations:\n" + for key, value in results['recommendations'].items(): + response += f"- {key}: {value}\n" + + return response + + except Exception as e: + return f"Error in wirelength model evaluation: {str(e)}" + + def _generate_parameters_with_existing(self, count: int, data: Dict) -> str: + """Generate parameters using existing functions""" + try: + if count <= 0 or count > 50: + return "Error: count must be between 1 and 50" + + # Obtain parameter dimensions + n_dims = len(self.parameter_names) + + # Use existing Latin hypercube sampling + samples = latin_hypercube(count, n_dims) + + response = f"Parameter Generation using Latin Hypercube:\n" + response += f"- Samples generated: {count}\n" + response += f"- Parameter dimensions: {n_dims}\n" + response += f"- Sampling method: Latin Hypercube\n" + + # Display parameter range information + response += "\nParameter Ranges:\n" + for i, param in enumerate(self.parameter_names): + constraint = self.param_constraints[param] + min_val, max_val = constraint['range'] + response += f"- {param}: [{min_val}, {max_val}] ({constraint['type']})\n" + + return response + + except Exception as e: + return f"Error in parameter generation: {str(e)}" + + def _latin_hypercube_sampling_with_existing(self, config: Dict, data: Dict) -> str: + """Using existing functions for Latin hypercube sampling""" + try: + n_points = config.get('n_points', 10) + n_dims = len(self.parameter_names) + + # Use the existing Latin hypercube sampling function + samples = latin_hypercube(n_points, n_dims) + + response = f"Latin Hypercube Sampling:\n" + response += f"- Points: {n_points}\n" + response += f"- Dimensions: {n_dims}\n" + response += f"- Sample shape: {samples.shape}\n" + + # Display sampling statistics + response += f"- Sample range: [{samples.min():.3f}, {samples.max():.3f}]\n" + response += f"- Sample mean: {samples.mean():.3f}\n" + response += f"- Sample std: {samples.std():.3f}\n" + + return response + + except Exception as e: + return f"Error in Latin hypercube sampling: {str(e)}" + + def _configure_selection_with_existing(self, config: Dict, data: Dict) -> str: + """Configure selection strategy using existing functions""" + try: + method = config.get('method', 'hybrid') + quality_weight = config.get('quality_weight', 0.7) + uncertainty_bonus = config.get('uncertainty_bonus', 0.2) + n_points = config.get('n_points', 10) + + response = f"Selection Strategy Configured:\n" + response += f"- Method: {method}\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Uncertainty bonus: {uncertainty_bonus}\n" + response += f"- Points to select: {n_points}\n" + + # Provide explanations for different methods + method_descriptions = { + "kmeans": "K-means clustering - selects best point from each cluster", + "hybrid": "Hybrid approach - balances quality and diversity", + "entropy": "Entropy-based - maximizes information diversity", + "graph": "Graph-based - uses network centrality measures" + } + + response += f"Method description: {method_descriptions.get(method, 'No description')}\n" + + return response + + except Exception as e: + return f"Error in selection configuration: {str(e)}" + + + def _create_quality_scores_with_existing(self, config: Dict, data: Dict) -> str: + """Create a quality score using an existing function""" + try: + # Extract necessary information from data + X, Y = self._extract_XY_from_data(data) + + if X is not None and Y is not None: + # Simulation model predictions and uncertainties (in practical use, these should come from real models) + model_predictions = Y # Using real values as a proxy for prediction + model_uncertainties = np.ones_like(Y) * 0.1 # Simulate uncertainty + + # Create a quality score using an existing function + quality_scores = create_quality_scores(X, Y, model_predictions, model_uncertainties) + + response = "Quality Scores Created:\n" + response += f"- Data points: {len(X)}\n" + response += f"- Quality score range: [{quality_scores.min():.4f}, {quality_scores.max():.4f}]\n" + response += f"- Quality score mean: {quality_scores.mean():.4f}\n" + response += f"- Quality score std: {quality_scores.std():.4f}\n" + + response += f"- First 5 quality scores: {quality_scores[:5].tolist()}\n" + + if 'selection_data' not in data: + data['selection_data'] = {} + data['selection_data']['quality_scores'] = quality_scores + data['selection_data']['X'] = X + data['selection_data']['Y'] = Y + + return response + else: + return "No data available for quality score creation" + + except Exception as e: + return f"Error in quality score creation: {str(e)}" + + def _select_points_with_existing(self, config: Dict, data: Dict) -> str: + """_select_points_with_existing""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + method = config.get('method', 'hybrid') + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + selection_config = { + "quality_weight": quality_weight, + "uncertainty_bonus": config.get('uncertainty_bonus', 0.2) + } + + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points, + config=selection_config + ) + + response = f"Points Selected using {method.upper()} method:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Selected quality scores: {selected_qualities.tolist()}\n" + response += f"- Average quality of selected: {selected_qualities.mean():.4f}\n" + + # store selection data + data['selection_data']['selected_indices'] = selected_indices + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in point selection: {str(e)}" + + def _compare_selection_methods_with_existing(self, config: Dict, data: Dict) -> str: + """compare selection methods with existing(""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 5) + methods = ['kmeans', 'hybrid', 'entropy', 'graph'] + + response = "Selection Method Comparison:\n" + response += f"- Comparing {len(methods)} methods\n" + response += f"- Points to select: {n_points}\n\n" + + for method in methods: + try: + selected_indices = select_points( + X, quality_scores, + method=method, + n_points=n_points + ) + + selected_qualities = quality_scores[selected_indices] + + response += f"**{method.upper()}**:\n" + response += f" - Selected indices: {selected_indices.tolist()}\n" + response += f" - Avg quality: {selected_qualities.mean():.4f}\n" + response += f" - Quality range: [{selected_qualities.min():.4f}, {selected_qualities.max():.4f}]\n" + + except Exception as e: + response += f"**{method.upper()}**: Error - {str(e)}\n" + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in method comparison: {str(e)}" + + def _kmeans_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using K-means selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using K-means selecting function + selected_indices = kmeans_select(X, quality_scores, n_points) + + response = "K-means Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + response += f"- Quality diversity: {selected_qualities.std():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'kmeans' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in K-means selection: {str(e)}" + + def _hybrid_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing hybrid selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + quality_weight = config.get('quality_weight', 0.7) + + distance_matrix = cdist(X, X) + + # using hybrid_select function + selected_indices = hybrid_select( + X, quality_scores, distance_matrix, + n_points, quality_weight + ) + + response = "Hybrid Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Quality weight: {quality_weight}\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + selected_points = X[selected_indices] + min_distances = np.min(cdist(selected_points, selected_points) + np.eye(len(selected_points)) * 1e6, axis=1) + response += f"- Minimum inter-point distance: {min_distances.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'hybrid' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in hybrid selection: {str(e)}" + + def _entropy_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing entropy selecting methods""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using entropy selecting function + selected_indices = entropy_select(X, quality_scores, n_points) + + response = "Entropy-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'entropy' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in entropy selection: {str(e)}" + + def _graph_selection_with_existing(self, config: Dict, data: Dict) -> str: + """using existing graph selection method""" + try: + selection_data = data.get('selection_data', {}) + quality_scores = selection_data.get('quality_scores') + X = selection_data.get('X') + + if X is not None and quality_scores is not None: + n_points = config.get('n_points', 10) + + # using graph selecting function + selected_indices = graph_select(X, quality_scores, n_points) + + response = "Graph-based Selection Results:\n" + response += f"- Selected {len(selected_indices)} points\n" + response += f"- Selected indices: {selected_indices.tolist()}\n" + + selected_qualities = quality_scores[selected_indices] + response += f"- Average quality: {selected_qualities.mean():.4f}\n" + + # store results + data['selection_data']['selected_indices'] = selected_indices + data['selection_data']['method_used'] = 'graph' + + return response + else: + return "No quality scores available. Please run 'create_quality_scores' first." + + except Exception as e: + return f"Error in graph selection: {str(e)}" + + + def _validate_parameters_tool(self, params: Dict) -> str: + validation_results = [] + + for param_name, value in params.items(): + if param_name in self.param_constraints: + constraint = self.param_constraints[param_name] + min_val, max_val = constraint['range'] + param_type = constraint['type'] + + if value < min_val or value > max_val: + validation_results.append(f" {param_name}={value} outside range [{min_val}, {max_val}]") + else: + validation_results.append(f" {param_name}={value} within valid range") + + if self._validate_domain_constraints(params): + validation_results.append("Domain constraints satisfied") + else: + validation_results.append("Domain constraints violated") + + return "Parameter Validation:\n" + "\n".join(validation_results) + + + def _load_config(self) -> Dict[str, Any]: + """Load the configuration from 'opt_config.json'.""" + with open('opt_config.json', 'r') as f: + config = json.load(f) + return config + + def _load_initial_params(self) -> Dict[str, Any]: + """Load initial parameters from the design's config.mk file""" + config_path = f"designs/{self.platform}/{self.design}/config.mk" + params = {} + with open(config_path, 'r') as f: + for line in f: + if line.startswith('export'): + parts = line.strip().split('=', 1) + if len(parts) == 2: + key = parts[0].replace('export', '').strip() + value = parts[1].strip() + params[key] = value + return params + + def _load_sdc_context(self) -> Dict[str, Any]: + """Load SDC context including special case for JPEG""" + sdc_context = {} + + # Determine SDC filename based on platform/design + if self.platform.lower() == 'asap7' and self.design.lower() == 'jpeg': + sdc_file = 'jpeg_encoder15_7nm.sdc' + else: + sdc_file = 'constraint.sdc' + + sdc_path = f"designs/{self.platform}/{self.design}/{sdc_file}" + + # Read SDC file + try: + with open(sdc_path, 'r') as f: + sdc_content = f.read() + + # Extract clock period + clock_period_match = re.search(r'set clk_period\s+([\d.]+)', sdc_content) + if clock_period_match: + sdc_context['clock_period'] = float(clock_period_match.group(1)) + + # Store full content for context + sdc_context['content'] = sdc_content + sdc_context['filename'] = sdc_file + + except Exception as e: + print(f"Warning: Could not load SDC file {sdc_path}: {str(e)}") + sdc_context['error'] = str(e) + + return sdc_context + + + def _generate_llm_prompt(self, stage: str, data: Dict[str, Any]) -> str: + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + param_type = info['type'] + param_range = info['range'] + constraints_text += f"- {param} ({param_type}, range: {param_range})\n" + + # tool_instructions = { + # 'inspect': ( + # f"**Stage: Inspect**\n" + # "In this stage, we analyze the data from previous optimization runs to identify patterns, trends, and insights.\n\n" + # f"Data to analyze:\n{json.dumps(data, indent=2, default=str)}\n\n" + # "Please analyze the data and provide insights on:\n" + # "1. Key patterns in successful vs unsuccessful runs.\n" + # "2. Parameter ranges that appear promising.\n" + # "3. Any timing or wirelength trends.\n" + # "4. Recommendations for subsequent runs.\n" + # "5. We hope to further reduce the total wirelength.\n" + # ), + + # 'model': ( + # f"**Stage: Model**\n" + # "In this stage, we decide how to model the optimization problem based on the data analysis.\n\n" + # f"Data for modeling:\n{json.dumps(data, indent=2, default=str)}\n\n" + # "Please suggest:\n" + # "1. Appropriate modeling techniques.\n" + # "2. Key parameters to focus on.\n" + # "3. Surrogate model recommendations.\n" + # "4. Acquisition function choices.\n" + # ), + + # 'agglomerate': ( + # f"**Stage: Agglomerate**\n" + # "In this stage, we generate new parameter combinations to explore in the next optimization runs.\n\n" + # "Please provide a list of new parameter sets to try, ensuring they respect the domain constraints below.\n\n" + # f"{constraints_text}\n" + # "Each parameter set should be a dictionary with parameter names and their suggested values.\n" + # "**Important:** Make sure all parameter sets satisfy the domain constraints before suggesting them.\n" + # ) + # } + + data_context = "" + if stage == 'inspect': + data_context = f"\nData to analyze:\n{json.dumps(data, indent=2, default=str)}\n" + elif stage == 'model': + data_context = f"\nData for modeling:\n{json.dumps(data, indent=2, default=str)}\n" + elif stage == 'agglomerate': + data_context = f"\nDomain Constraints to respect:\n{constraints_text}\n" + + stage_contexts = { + 'inspect': ( + f"metrics analyze: Total runs={data.get('log_data', {}).get('summary', {}).get('total_runs', 0)}, " + f"successful runs ={data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)}" + ), + 'model': "Configure modeling methods based on inspection results", + 'agglomerate': "Configure parameter selection strategy based on modeling results" + } + + prompt = f"""**stages:{stage.upper()}** + {self.tool_instructions.get(stage, '')} + + {data_context} + + {stage_contexts.get(stage, '')} + + **Important: Use only tool calls and do not generate text replies!** + """ + + # ========= Splicing RAG ========= + rag_context = "" + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + + # Step 1: Extract error information + error_summary = "" + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + if all_errors: + # Retrieve the most recent or frequent errors + top_errors = all_errors[-3:] # Last 3 posts + error_summary = "\n".join(top_errors) + print(f"[DEBUG] Detected {len(all_errors)} error messages. Sample:\n{error_summary}") + + # Step 2: Construct RAG query + if error_summary: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"The recent optimization runs failed with errors:\n{error_summary}\n\n" + "Retrieve relevant OpenROAD documentation, known failure modes, and " + "potential parameter tuning suggestions that may fix these issues." + ) + else: + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + + # Step 3: Execute search + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict, + ) + + if isinstance(rag_context, dict): # If returning dict + print(f"[DEBUG] RAG Retrieved {len(rag_context.get('docs', []))} related entries.") + for doc in rag_context.get("docs", [])[:3]: + print(f" ↳ {doc['title']} (score={doc['score']:.3f}) from {doc['source']}") + retrieved_text = rag_context.get("content", "") + else: + retrieved_text = rag_context + + # Step 4: 加入 prompt + if retrieved_text.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{retrieved_text}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + if "log_data" in data: + all_errors = [] + for run in data["log_data"].get("runs", []): + if run.get("errors"): + all_errors.extend(run["errors"]) + + if all_errors: + error_summary = "\n".join(all_errors[-5:]) # The last 5 errors + prompt += f""" + + ### Detected Run Errors + {error_summary} + + The model must now act as an **EDA Debugging Assistant**. + Using the retrieved documentation and knowledge, analyze the errors above and: + 1. Identify the root causes of each error (e.g., tool misconfiguration, parameter overflow, timing issues, etc.) + 2. Suggest **specific parameter changes or flow adjustments** to prevent these errors. + 3. Indicate whether the error is likely due to constraints, routing congestion, or timing margin. + 4. Provide a short explanation for each suggestion. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + + """ + print("[DEBUG] Added error-fix section to prompt.") + def _collect_recent_errors(self, data: Dict[str, Any], max_errors=5) -> str: + errors = [] + for run in data.get("log_data", {}).get("runs", []): + if run.get("errors"): + errors.extend(run["errors"]) + print(f"[DEBUG] Found total {len(errors)} errors in all runs.") + return "\n".join(errors[-max_errors:]) if errors else "No errors detected." + + def _call_llm(self, stage: str, data: Dict[str, Any]) -> Dict[str, Any]: + # """Call Claude to get recommendations for optimization parameters""" + # print(f"\n=== Calling LLM for {stage} stage ===") + """Call LLM to get recommendations for optimization parameters using react framework""" + print(f"\n=== Calling LLM with ReAct framework for {stage} stage ===") + + try: + react_prompt = self._generate_react_prompt(stage, data) + print(f"Generated prompt with context for {stage}") + print("=== Context Message ===") + print(react_prompt) + print("========================") + available_tools = self._create_react_tools(stage, data) + + react_result = self.react_framework.run_react_cycle( + initial_prompt=react_prompt, + available_tools=available_tools, + max_steps=3, + temperature=0.1 + ) + # === If an error occurs, enter Debug mode === + if "log_data" in data and any(run.get("errors") for run in data["log_data"].get("runs", [])): + print("\n[DEBUG] Detected errors in previous runs. Invoking Debug Assistant mode...") + + # Collect error information + all_errors = [] + for run in data["log_data"]["runs"]: + if run.get("errors"): + all_errors.extend(run["errors"]) + error_text = "\n".join(all_errors[-5:]) # Recent entries + + # Construct a Debug Prompt + debug_prompt = f""" + You are now an **EDA Debugging Expert**. + Based on the following OpenROAD errors and RAG documentation, analyze and provide concrete repair suggestions. + + Errors Detected: + {error_text} + + Please identify: + 1. Root cause of each error. + 2. Specific parameter changes (e.g., in floorplan, CTS, or routing stages) that could fix the issue. + 3. Whether this issue is due to timing, congestion, or setup misconfiguration. + 4. One short explanation per fix. + + Return your answer in **JSON format** like: + {{ + "error_analysis": [ + {{ + "error": "...", + "cause": "...", + "fix": "...", + "params_to_adjust": {{"param_name": "new_value"}} + }} + ] + }} + """ + + # Call LLM to output repair suggestions + debug_result = self.react_framework.run_react_cycle( + initial_prompt=debug_prompt, + available_tools=available_tools, + max_steps=1, + temperature=0.2 + ) + + print("\n[DEBUG] LLM Debug Assistant Result:") + print(debug_result.get("final_answer", "")) + + # Save repair suggestions to the main results + react_result["error_fix_suggestions"] = debug_result.get("final_answer", "") + # Write files for manual viewing + with open("logs/error_fix_suggestions.json", "w") as f: + f.write(debug_result.get("final_answer", "")) + print(f"\n=== ReAct Cycle Completed ===") + print(f"Completed steps: {react_result.get('completed_steps', 0)}/{react_result.get('max_steps', 8)}") + print(f"Final Answer: {react_result['final_answer']}") + + configs = self._parse_react_final_answer(react_result["final_answer"], stage) + + if react_result.get('reasoning_history'): + print(f"\n=== Reasoning History ({len(react_result['reasoning_history'])} steps) ===") + for step in react_result['reasoning_history']: + print(f"Step {step['step']}: {step.get('thought', 'No thought')}") + + print(f"Returning config for stage '{stage}': {configs}") + return configs + + except Exception as e: + print(f"Error in LLM call for stage {stage}: {e}") + default_config = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'agglomerate': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + return default_config.get(stage, {}) + + + def _generate_react_prompt(self, stage: str, data: Dict[str, Any]) -> str: + """generate prompts of ReAct framework""" + + stage_descriptions = { + 'inspect': ( + "You are an expert EDA optimization analyst. Analyze the optimization run data to identify patterns " + "and insights. Use the available tools to examine data distributions, correlations, and successful " + "parameter ranges. Your goal is to understand what makes runs successful and provide recommendations " + "for the modeling stage." + ), + 'model': ( + "You are an expert machine learning engineer for EDA optimization. Based on the inspection results, " + "configure the modeling approach for Bayesian optimization. Consider kernel selection, acquisition " + "functions, and surrogate modeling strategies. Balance exploration and exploitation based on the data." + ), + 'agglomerate': ( + "You are an expert parameter optimization specialist. Generate new parameter combinations for the " + "next optimization iteration. Use insights from previous stages to focus on promising regions while " + "maintaining diversity. Ensure all parameters satisfy the domain constraints." + ) + } + + constraints_text = "Parameter Constraints:\n" + for param, info in self.param_constraints.items(): + constraints_text += f"- {param} ({info['type']}, range: {info['range']})\n" + + react_format_instructions = """ +**ReAct Framework Instructions - MUST FOLLOW THIS FORMAT:** + +1. **Thought**: Analyze the current situation and decide what to do next +2. **Action**: Choose one tool from the available tools +3. **Action Input**: Provide the appropriate input for the chosen tool +4. **Observation**: Wait for the tool's response, then continue reasoning + +**Available Tools**: You have access to various analysis tools. Use them to gather information before making decisions. + +**DO NOT include Final Answer until you have completed all necessary analysis.** +**DO NOT predict or simulate tool observations.** +**You will receive actual Observation from tools before continuing.** + +Only after proper analysis: +**Final Answer Format**: Only when you have completed your analysis, provide: +Final Answer: {your_configuration_here} + +**Example**: +Thought: I need to understand the data patterns first. Let me analyze the success rates. +Action: analyze_data_patterns +Action Input: {} +Observation: [Tool response...] +Thought: Now I need to check parameter correlations... +Action: analyze_correlations +Action Input: {} +Observation: [Tool response...] +Final Answer: {"n_clusters": 5, "correlation_threshold": 0.7} +""" + + prompt = f""" + {stage_descriptions[stage]} + + **Current Stage**: {stage.upper()} + **Objective**: {self.objective} + **Platform**: {self.platform} + **Design**: {self.design} + + **Available Data**: + - Total runs: {data.get('log_data', {}).get('summary', {}).get('total_runs', 0)} + - Successful runs: {data.get('log_data', {}).get('summary', {}).get('successful_runs', 0)} + - Failed runs: {data.get('log_data', {}).get('summary', {}).get('failed_runs', 0)} + + {constraints_text} + {react_format_instructions} + + Begin your analysis: + """ + + rag_context = "" + # ======== extract errors ======== + error_summary = self._collect_recent_errors(data) + if error_summary and "No errors" not in error_summary: + print("[DEBUG] RAG: Detected error summary, adding error analysis prompt...") + prompt += f""" + + ### Detected Run Errors + {error_summary} + + You are now acting as an **EDA Debugging Assistant**. + Analyze the errors above and: + 1. Identify the root causes. + 2. Suggest specific parameter changes. + 3. Indicate whether the error is due to timing, routing, or constraints. + 4. Provide short explanations for each. + + Output format: + Error Diagnosis: + - Root Cause: ... + - Recommended Fix: ... + - Suggested Parameter Change: ... + - Reason: ... + """ + else: + print("[DEBUG] No errors found in logs for this stage.") + if getattr(self, "supervision_feedback", ""): + prompt += f""" + + ### Supervisor Feedback + {self.supervision_feedback} + + Please prioritize these supervisor notes when making decisions in this stage. + """ + print("[SUPERVISOR][DEBUG] Added supervisor feedback into prompt.") + if self.rag_model is not None and self.rag_embeddings is not None: + try: + print("[DEBUG] RAG: Starting retrieval...") + query = ( + f"Stage: {stage}. Objective: {self.objective}. " + f"Focus on analyzing {stage}-related optimization results. " + f"Important metrics include wirelength, timing, area, and success rate. " + f"Find relevant OpenROAD documentation, parameter tuning guides, and failure pattern examples." + ) + rag_context = answerWithRAG( + query, + self.rag_embeddings, + self.rag_model, + self.rag_docs, + self.rag_docsDict + ) + print(f"[DEBUG] RAG: Retrieved context length = {len(rag_context)}") + if rag_context.strip(): + prompt += ( + "\n\n=== Retrieved OpenROAD Documentation (via RAG) ===\n" + f"{rag_context}\n" + "==============================================" + ) + print("[DEBUG] RAG: Context successfully added to prompt.") + else: + print("[DEBUG] RAG: Empty context retrieved.") + except Exception as e: + prompt += f"\n\n[WARN] RAG retrieval failed: {e}" + + return prompt + + def _parse_react_final_answer(self, final_answer: str, stage: str) -> Dict[str, Any]: + """parse react final answer""" + + default_configs = { + 'inspect': {"n_clusters": 5, "correlation_threshold": 0.5}, + 'model': {"kernel_type": "matern", "preprocessing": "robust", + "acquisition": "ei", "surrogate_weight": 0.8}, + 'selection': {"method": "hybrid", "quality_weight": 0.7, + "uncertainty_bonus": 0.2} + } + + configs = {} + + if final_answer and "Reached maximum steps" not in final_answer: + try: + json_match = re.search(r'\{.*\}', final_answer, re.DOTALL) + if json_match: + extracted_config = json.loads(json_match.group()) + configs[stage] = extracted_config + print(f"✓ Extracted configuration from ReAct response: {extracted_config}") + else: + configs[stage] = default_configs.get(stage, {}) + print(f"Using default configuration for {stage} stage") + except Exception as e: + print(f"Error parsing ReAct final answer: {e}") + configs[stage] = default_configs.get(stage, {}) + else: + configs[stage] = default_configs.get(stage, {}) + print(f"ReAct failed to produce answer, using default for {stage}") + + return configs + + def run_iteration(self, num_runs: int) -> Dict[str, Any]: + """Run a single inspect-optimize-agglomerate flow and return its summary.""" + return self._execute_inspect_optimize_flow(num_runs, flow_index=0) + + # def run_dual_supervised_iterations(self, num_runs: int, num_flows: int) -> None: + # """ + # Run multiple inspect-optimize-agglomerate flows with supervisor feedback injected + # into the next flow's prompt. + # """ + # if num_flows <= 0: + # print("[WARN] num_flows must be >= 1, skipping execution.") + # return + + # self.supervision_feedback = "" + # for flow_index in range(num_flows): + # print(f"\n=== Dual-Supervised Flow {flow_index + 1}/{num_flows} ===") + # flow_summary = self._execute_inspect_optimize_flow(num_runs, flow_index=flow_index) + # supervisor_feedback = self._run_supervisor_review(flow_summary, flow_index) + # if supervisor_feedback: + # self.supervision_feedback = supervisor_feedback + # print("[SUPERVISOR] Stored feedback for the next flow iteration.") + # else: + # print("[SUPERVISOR] Supervisor produced no feedback; continuing without updates.") + + def run_dual_supervised_iterations(self, num_runs: int, num_flows: int) -> None: + if num_flows <= 0: + return + + for flow_index in range(num_flows): + print(f"\n=== Dual-Supervised Flow {flow_index + 1}/{num_flows} ===") + + # Run Flow (this will use the latest version from self.tool_instructions). + flow_summary = self._execute_inspect_optimize_flow(num_runs, flow_index=flow_index) + + # Get gradient (Supervisor Feedback) + supervisor_feedback = self._run_supervisor_review(flow_summary, flow_index) + + if supervisor_feedback and flow_index < num_flows - 1: + # [TextGrad Integration] 3. Perform Backpropagation Steps + # Here we assume we need to optimize the Prompt in the 'agglomerate' stage, as this is crucial for parameter generation. + # You can also intelligently decide which stage to optimize based on the feedback content. + print("[TextGrad] Backpropagating feedback to Agent Prompts...") + self._optimize_prompt_with_textgrad('agglomerate', supervisor_feedback) + self._optimize_prompt_with_textgrad('model', supervisor_feedback) + else: + print("[SUPERVISOR] No feedback or final iteration; skipping optimization.") + + def _execute_inspect_optimize_flow(self, num_runs: int, flow_index: int = 0) -> Dict[str, Any]: + """Internal helper containing the original inspect-optimize-agglomerate flow.""" + print(f"\n=== Starting optimization iteration #{flow_index + 1} for {self.platform}/{self.design} ===") + print(f"Objective: {self.objective}") + print(f"Number of runs requested: {num_runs}") + + # Step 1: Inspect logs + print("\nStep 1: Inspecting logs...") + log_data = self.inspect_logs() + print(f"Found {log_data['summary']['total_runs']} total runs, " + f"{log_data['summary']['successful_runs']} successful") + + # Get LLM recommendations for inspection and analysis + print("\nGetting LLM recommendations with ReAct framework for inspection...") + inspect_configs = self._call_llm('inspect', { + 'log_data': log_data, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context + }) + inspection_config = inspect_configs.get('inspect', {}) + print(f"React inspection config: {inspection_config}") + + # Step 2: Analyze metrics with LLM config + print("\nStep 2: Analyzing metrics ...") + metrics = self.analyze_metrics( + log_data, + n_clusters=inspection_config.get('n_clusters', 5), + correlation_threshold=inspection_config.get('correlation_threshold', 0.5) + ) + print(f"Processed metrics for {len(metrics.get('objectives', []))} successful runs") + + # Get LLM recommendations for modeling based on inspection results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for modeling...") + model_configs = self._call_llm('model', { + 'log_data': log_data, + 'metrics': metrics, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs + }) + model_config = model_configs.get('model', {}) + print(f"LLM model config: {model_config}") + + # Step 3: Evaluate models with LLM config + print("\nStep 3: Evaluating models...") + model_results = self.evaluate_models( + log_data, metrics, + model_config.get('kernel_type', 'matern'), + preprocessing=model_config.get('preprocessing', 'robust'), + acquisition=model_config.get('acquisition', 'ei'), + surrogate_weight=model_config.get('surrogate_weight', 0.8) + ) + + # Get LLM recommendations for parameter selection based on all previous results with ReAct framework + print("\nGetting LLM recommendations with ReAct framework for parameter selection...") + selection_configs = self._call_llm('agglomerate', { + 'log_data': log_data, + 'metrics': metrics, + 'model_results': model_results, + 'initial_params': self.initial_params, + 'sdc_context': self.sdc_context, + 'inspection_results': inspect_configs, + 'model_configs': model_configs + }) + selection_config = selection_configs.get('agglomerate', {}) + print(f"LLM selection config: {selection_config}") + + # Step 4: Generate parameters with LLM config + print("\nStep 4: Generating parameters...") + self.generate_parameters( + log_data, metrics, model_results, num_runs, + selection_method=selection_config.get('method', 'hybrid'), + quality_weight=selection_config.get('quality_weight', 0.7), + uncertainty_bonus=selection_config.get('uncertainty_bonus', 0.2) + ) + + flow_summary = { + "flow_index": flow_index, + "log_data": log_data, + "metrics": metrics, + "model_results": model_results, + "inspection_config": inspection_config, + "model_config": model_config, + "selection_config": selection_config, + "num_runs": num_runs, + "recent_errors": self._collect_recent_errors({"log_data": log_data}) + } + return flow_summary + + def _run_supervisor_review(self, flow_summary: Dict[str, Any], flow_index: int) -> str: + """ + Use a secondary model to critique the previous flow and return feedback + for the next prompt. + """ + flow_snapshot = { + "log_summary": flow_summary.get("log_data", {}).get("summary", {}), + "inspection_config": flow_summary.get("inspection_config", {}), + "model_config": flow_summary.get("model_config", {}), + "selection_config": flow_summary.get("selection_config", {}), + "recent_errors": flow_summary.get("recent_errors", ""), + "objective": self.objective, + "platform": self.platform, + "design": self.design, + } + + supervisor_prompt = ( + "You are the supervisor model for an EDA optimization agent.\n" + "The primary agent just finished an inspect-optimize-agglomerate flow.\n" + "Provide concise feedback (<=300 words) to guide the next flow. " + "Focus on:\n" + "1) What to adjust in inspection/model/selection configs,\n" + "2) Specific parameter or constraint reminders,\n" + "3) Warnings about errors or data issues.\n" + "Return plain text; start the message with 'Supervisor Feedback:'.\n" + f"Flow #{flow_index + 1} summary (JSON):\n{json.dumps(flow_snapshot, ensure_ascii=False, indent=2)}" + ) + print(f"[SUPERVISOR] Supervisor prompt: {supervisor_prompt}") + + try: + response = self.supervisor_client.chat.completions.create( + model=self.supervisor_model_name, + messages=[ + { + "role": "system", + "content": "You are a senior EDA optimization reviewer. Be concise and actionable.", + }, + {"role": "user", "content": supervisor_prompt}, + ], + temperature=0.2, + max_tokens=2048, + ) + feedback = response.choices[0].message.content.strip() + print(f"[SUPERVISOR] Feedback generated (len={len(feedback)}).") + return feedback + except Exception as e: + print(f"[SUPERVISOR] Failed to generate feedback: {e}") + return "" + + def inspect_logs(self) -> Dict[str, Any]: + """Step 1: Inspect all .log and .json logs recursively""" + log_dir = "logs" + pattern = f"{self.platform}_{self.design}_run" + + log_data = { + 'runs': [], + 'summary': { + 'total_runs': 0, + 'successful_runs': 0, + 'failed_runs': 0 + } + } + + if not os.path.exists(log_dir): + return log_data + + run_groups = {} + + for root, _, files in os.walk(log_dir): + for log_file in files: + if log_file.endswith(('.log', '.json')): + log_path = os.path.join(root, log_file) + + if log_file.startswith(pattern) or (self.platform in root and self.design in root): + + run_id = "main" + m = re.search(r'_run(\d+)\.log$', log_file) + if m: + run_id = f"base_{m.group(1)}" + + elif 'base_' in root: + run_id = os.path.basename(root) + + run_data = process_log_file(log_path) + + if run_id not in run_groups: + run_groups[run_id] = { + 'run_id': run_id, + 'success': True, + 'metrics': {}, + 'errors': [], + 'files': [] + } + + run_groups[run_id]['success'] &= run_data.get('success', True) + run_groups[run_id]['files'].append(log_path) + + if 'metrics' in run_data and run_data['metrics']: + run_groups[run_id]['metrics'].update(run_data['metrics']) + + if 'errors' in run_data and run_data['errors']: + run_groups[run_id]['errors'].extend(run_data['errors']) + + for run_id, run_data in run_groups.items(): + print(f"DEBUG: Run {run_id} success: {run_data['success']}") + print(f"DEBUG: Run {run_id} metrics: {run_data['metrics']}") + print(f"DEBUG: Run {run_id} errors: {run_data['errors']}") + print(f"DEBUG: Run {run_id} files: {run_data['files']}") + + log_data['runs'].append(run_data) + log_data['summary']['total_runs'] += 1 + if run_data['success']: + log_data['summary']['successful_runs'] += 1 + else: + log_data['summary']['failed_runs'] += 1 + + return log_data + + + def analyze_metrics(self, log_data: Dict[str, Any], n_clusters: int, correlation_threshold: float) -> Dict[str, Any]: + """Step 2: Analyze metrics from log data with improved analysis""" + metrics = { + 'objectives': [], + 'surrogates': [], + 'correlations': {}, + 'structure_analysis': {} + } + + # Extract feature vectors and objectives + feature_vectors = [] + objective_values = [] + surrogate_values = [] + + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + run_metrics = run['metrics'] + obj_values = self._calculate_objective(run) + + if obj_values['value'] is not None or obj_values['surrogate'] is not None: + # Extract parameter values as features + params = [] + for param in self.parameter_names: + params.append(float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0)))) + feature_vectors.append(params) + + objective_values.append(obj_values['value'] if obj_values['value'] is not None else np.nan) + surrogate_values.append(obj_values['surrogate'] if obj_values['surrogate'] is not None else np.nan) + + # Track correlations and other metrics + if obj_values['value'] is not None: + metrics['objectives'].append(obj_values['value']) + if obj_values['surrogate'] is not None: + metrics['surrogates'].append(obj_values['surrogate']) + + if obj_values['value'] is not None and obj_values['surrogate'] is not None: + if 'real_vs_surrogate' not in metrics['correlations']: + metrics['correlations']['real_vs_surrogate'] = [] + metrics['correlations']['real_vs_surrogate'].append({ + 'real': obj_values['value'], + 'surrogate': obj_values['surrogate'] + }) + + if feature_vectors: + X = np.array(feature_vectors) + Y = np.array(objective_values) + Y_surrogate = np.array(surrogate_values) + + # Use improved inspection functions + metrics['distribution_analysis'] = inspect_data_distribution(X, Y, Y_surrogate) + metrics['structure_analysis'] = inspect_data_structure(X, Y, { + 'n_clusters': n_clusters, + 'correlation_threshold': correlation_threshold + }) + + # Extract model recommendations if available (from new functions) + if 'model_recommendations' in metrics['structure_analysis']: + metrics['model_recommendations'] = metrics['structure_analysis']['model_recommendations'] + + # Add objective-specific metrics + if self.objective == 'ECP': + metrics['clock_period_impact'] = {} + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + period = float(run['metrics'].get('clock_period', 0)) + if period > 0: + if period not in metrics['clock_period_impact']: + metrics['clock_period_impact'][period] = { + 'final_slack': [], + 'cts_slack': [] + } + if 'worst_slack' in run['metrics']: + metrics['clock_period_impact'][period]['final_slack'].append( + float(run['metrics']['worst_slack'])) + if 'cts_ws' in run['metrics']: + metrics['clock_period_impact'][period]['cts_slack'].append( + float(run['metrics']['cts_ws'])) + + elif self.objective == 'DWL': + metrics['wirelength_progression'] = [] + for run in log_data['runs']: + if run['success'] and 'metrics' in run: + if 'cts_wirelength' in run['metrics'] and 'total_wirelength' in run['metrics']: + metrics['wirelength_progression'].append({ + 'cts': float(run['metrics']['cts_wirelength']), + 'final': float(run['metrics']['total_wirelength']) + }) + + return metrics + + + def evaluate_models(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + kernel_type: str, preprocessing: str, acquisition: str, surrogate_weight: float) -> Dict[str, Any]: + """Step 3: Use improved model functions to evaluate parameter quality""" + model_results = {} + + # Build context from log data and metrics + context = { + 'log_data': log_data, + 'metrics': metrics, + 'design_config': self.design_config, + 'initial_params': self.initial_params, + 'model_recommendations': metrics.get('model_recommendations', {}) + } + + # Use model recommendations if available (from new functions) + if 'model_recommendations' in metrics: + kernel_type = metrics['model_recommendations'].get('kernel_type', kernel_type) + preprocessing = 'robust' if metrics['model_recommendations'].get('needs_feature_scaling', True) else 'none' + + # Call appropriate model functions with improved modeling + if self.objective == 'ECP': + model_results = evaluate_timing_model(context) + elif self.objective == 'DWL': + model_results = evaluate_wirelength_model(context) + + # Add model configuration used + model_results['configuration'] = { + 'kernel_type': kernel_type, + 'preprocessing': preprocessing, + 'acquisition': acquisition, + 'surrogate_weight': surrogate_weight + } + + return model_results + + def generate_parameters(self, log_data: Dict[str, Any], metrics: Dict[str, Any], + model_results: Dict[str, Any], num_runs: int, + selection_method: str = 'hybrid', quality_weight: float = 0.7, + uncertainty_bonus: float = 0.2, model_config: Dict[str, Any] = None) -> None: + """Step 4: Generate parameter combinations and write to CSV""" + # Get list of parameters to optimize from constraints + param_names = list(self.param_constraints.keys()) + print(f"\nGenerating parameters for {len(param_names)} variables:") + for name in param_names: + print(f" - {name}: {self.param_constraints[name]}") + + # Extract successful runs for training data + successful_params = [] + successful_objectives = [] + for run in log_data.get('runs', []): + if run.get('success', False) and 'metrics' in run: + params = {} + for param in param_names: + params[param] = float(run.get('parameters', {}).get(param, self.initial_params.get(param, 0))) + successful_params.append(params) + + obj = self._calculate_objective(run) + successful_objectives.append(obj['value'] if obj['value'] is not None else obj['surrogate']) + + print(f"Using {len(successful_params)} successful runs as training data") + + # Convert to numpy arrays + if successful_params: + X = np.array([[params[name] for name in param_names] for params in successful_params]) + y = np.array(successful_objectives) + else: + print("Warning: No successful runs, using initial parameters as base") + X = np.array([[float(self.initial_params.get(name, 0)) for name in param_names]]) + y = np.array([0.0]) + + # Get kernel type from model config + kernel_type = model_config.get('kernel_type', 'matern') if model_config else 'matern' + print(f"\nCreating surrogate model with {kernel_type} kernel") + model = create_model(X, y, kernel_type=kernel_type) + + # Generate candidates + n_candidates = num_runs * 10 + print(f"Generating {n_candidates} candidate points") + candidates = latin_hypercube(n_candidates, len(param_names)) + + # Scale candidates to parameter ranges + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + candidates[:, i] = candidates[:, i] * (max_val - min_val) + min_val + + # Get predictions + predictions, uncertainties = model.predict(candidates, return_std=True) + + # Select points + print(f"\nSelecting points using {selection_method} method") + print(f"Quality weight: {quality_weight}, Uncertainty bonus: {uncertainty_bonus}") + quality_scores = create_quality_scores(candidates, y, predictions, uncertainties) + selected_indices = select_points( + candidates, quality_scores, + method=selection_method, + n_points=num_runs, + config={"quality_weight": quality_weight, + "uncertainty_bonus": uncertainty_bonus} + ) + + selected_params = candidates[selected_indices] + + # Validate domain constraints + print("\nValidating domain constraints...") + valid_params = [] + for params in selected_params: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + else: + print("Warning: Parameter set failed domain constraints") + + print(f"Found {len(valid_params)} valid parameter sets out of {len(selected_params)}") + + # Generate more if needed + while len(valid_params) < num_runs: + needed = num_runs - len(valid_params) + print(f"Generating {needed} additional parameter sets...") + new_candidates = latin_hypercube(needed, len(param_names)) + for i, param in enumerate(param_names): + constraints = self.param_constraints[param] + min_val = float(constraints['range'][0]) + max_val = float(constraints['range'][1]) + new_candidates[:, i] = new_candidates[:, i] * (max_val - min_val) + min_val + + for params in new_candidates: + param_dict = {name: value for name, value in zip(param_names, params)} + if self._validate_domain_constraints(param_dict): + valid_params.append(param_dict) + if len(valid_params) >= num_runs: + break + + # Write to CSV + print(f"\nWriting {num_runs} parameter sets to CSV...") + self._write_params_to_csv(valid_params[:num_runs]) + + def _calculate_objective(self, run: Dict[str, Any]) -> Dict[str, float]: + """Calculate objective value and surrogate from run metrics""" + metrics = run.get('metrics', {}) + result = {'value': None, 'surrogate': None} + + if self.objective == 'ECP': + if 'clock_period' in metrics: + period = float(metrics['clock_period']) + # Real ECP from final worst slack + if 'worst_slack' in metrics: + result['value'] = period - float(metrics['worst_slack']) + # Surrogate ECP from CTS worst slack + if 'cts_ws' in metrics: + result['surrogate'] = period - float(metrics['cts_ws']) + + elif self.objective == 'DWL': + # Real wirelength from detailed route + if 'total_wirelength' in metrics: + result['value'] = float(metrics['total_wirelength']) + # Surrogate wirelength from CTS + if 'cts_wirelength' in metrics: + result['surrogate'] = float(metrics['cts_wirelength']) + + elif self.objective == 'COMBO': + # Get weights from environment variables + try: + ecp_weight = float(os.environ.get('ECP_WEIGHT')) + wl_weight = float(os.environ.get('WL_WEIGHT')) + ecp_weight_surrogate = float(os.environ.get('ECP_WEIGHT_SURROGATE')) + wl_weight_surrogate = float(os.environ.get('WL_WEIGHT_SURROGATE')) + except (ValueError, TypeError): + raise ValueError("Weights not properly set in environment variables.") + + # Calculate real ECP and WL values + ecp_value = None + wl_value = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'worst_slack' in metrics: + ecp_value = clock_period - float(metrics['worst_slack']) + if 'total_wirelength' in metrics: + wl_value = float(metrics['total_wirelength']) + + # Calculate surrogate ECP and WL values + ecp_surrogate = None + wl_surrogate = None + if 'clock_period' in metrics: + clock_period = float(metrics['clock_period']) + if 'cts_ws' in metrics: + ecp_surrogate = clock_period - float(metrics['cts_ws']) + if 'cts_wirelength' in metrics: + wl_surrogate = float(metrics['cts_wirelength']) + + # Calculate weighted objective for real values + if ecp_value is not None and wl_value is not None: + result['value'] = ecp_weight * ecp_value + wl_weight * wl_value + elif ecp_value is not None: + result['value'] = ecp_weight * ecp_value + elif wl_value is not None: + result['value'] = wl_weight * wl_value + + # Calculate weighted surrogate objective + if ecp_surrogate is not None and wl_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + wl_weight_surrogate * wl_surrogate + elif ecp_surrogate is not None: + result['surrogate'] = ecp_weight_surrogate * ecp_surrogate + elif wl_surrogate is not None: + result['surrogate'] = wl_weight_surrogate * wl_surrogate + + return result + + def _validate_domain_constraints(self, params: Dict[str, Any]) -> bool: + """Validate parameter combinations against domain constraints""" + # 1. Core utilization vs cell padding + core_util = float(params.get('core_util', 0)) + gp_pad = float(params.get('cell_pad_global', 0)) + dp_pad = float(params.get('cell_pad_detail', 0)) + + if core_util > 80 and (gp_pad > 2 or dp_pad > 2): + print(f"Domain constraint failed: core_util > 80 and gp_pad > 2 or dp_pad > 2") + return False + + # 2. TNS end percent vs place density + tns_end = float(params.get('tns', 0)) + place_density = float(params.get('lb_addon', 0)) + + if tns_end < 70 and place_density > 0.7: + print(f"Domain constraint failed: tns_end < 70 and place_density > 0.7") + return False + + # 3. CTS cluster constraints + cts_size = float(params.get('cts_size', 0)) + cts_diameter = float(params.get('cts_diameter', 0)) + + if cts_size > 30 and cts_diameter < 100: + print(f"Domain constraint failed: cts_size > 30 and cts_diameter < 100") + return False + + return True + + def _write_params_to_csv(self, params_list: List[Dict[str, Any]]) -> None: + """Write the new parameter sets to the expected CSV file for the next iteration""" + csv_file = f"designs/{self.platform}/{self.design}/{self.platform}_{self.design}.csv" + + # Ensure parameters are in correct order and properly typed + with open(csv_file, 'w', newline='\n') as f: # Explicitly use Unix line endings + writer = csv.writer(f) + # Write header in correct order + writer.writerow(self.parameter_names) + + # Write parameter rows + for params in params_list: + row = [] + for param_name in self.parameter_names: + value = params.get(param_name) + if value is None: + print(f"Warning: Missing value for parameter {param_name}") + continue + + # Apply type constraints + constraint = self.param_constraints[param_name] + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param_name} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + + except (ValueError, TypeError) as e: + print(f"Error converting {param_name} value '{value}' to {param_type}: {e}") + continue + + row.append(value) + + if len(row) == len(self.parameter_names): + writer.writerow(row) + else: + print(f"Warning: Skipping incomplete parameter set") + + print(f"New parameter sets written to {csv_file}") + + def _parse_llm_output(self, llm_response: str) -> List[Dict[str, Any]]: + """Parse the LLM's response and enforce parameter constraints""" + try: + param_sets = json.loads(llm_response) + except json.JSONDecodeError as e: + print(f"Error parsing LLM response: {e}") + return [] + + constrained_params = [] + for param_set in param_sets: + ordered_params = {} + valid = True + for param in self.parameter_names: + value = param_set.get(param) + if value is None: + print(f"Parameter '{param}' is missing in the LLM output.") + valid = False + break + + constraint = self.param_constraints.get(param) + if constraint: + param_type = constraint['type'] + param_range = constraint['range'] + + try: + # First convert to float for uniform handling + value = float(value) + + # Apply range constraints if they exist + if param_range is not None: + min_val, max_val = param_range + range_size = max_val - min_val + + # If value is too far out of range, resample uniformly + if value > max_val + range_size or value < min_val - range_size: + value = random.uniform(min_val, max_val) + print(f"Resampled {param} to {value} (was too far out of range)") + else: + # Otherwise just clamp to range + value = max(min_val, min(max_val, value)) + + # Convert to final type after range enforcement + if param_type == 'int': + value = int(round(value)) + elif param_type != 'float': + raise ValueError(f"Unsupported parameter type: {param_type}") + + ordered_params[param] = value + except (ValueError, TypeError) as e: + print(f"Parameter '{param}' has invalid value '{value}': {e}") + valid = False + break + else: + print(f"Unknown parameter '{param}' in parameter set.") + valid = False + break + + if valid and self._validate_domain_constraints(ordered_params): + constrained_params.append(ordered_params) + else: + print(f"Parameter set {ordered_params} failed validation and will be discarded.") + + return constrained_params + + def generate_initial_parameters(self, num_runs: int) -> None: + """Generate initial random parameters and write them to CSV using the same method as subsequent iterations""" + params_list = [] + for _ in range(num_runs): + params = {} + for param in self.parameter_names: + info = self.param_constraints[param] + param_type = info['type'] + min_value, max_value = info['range'] + if param_type == 'int': + value = random.randint(int(min_value), int(max_value)) + elif param_type == 'float': + value = random.uniform(min_value, max_value) + else: + continue # Skip unsupported types + params[param] = value + params_list.append(params) + + # Use the same method to write parameters to CSV + self._write_params_to_csv(params_list) + +def main(): + if len(sys.argv) not in (5, 6): + print("Usage: optimize_dual.py []") + sys.exit(1) + + platform = sys.argv[1] + design = sys.argv[2] + objective = sys.argv[3] + num_runs = int(sys.argv[4]) + num_flows = int(sys.argv[5]) if len(sys.argv) == 6 else 1 + + workflow = OptimizationWorkflow(platform, design, objective) + # Keep backward compatibility: a single flow behaves like the legacy run_iteration. + workflow.run_dual_supervised_iterations(num_runs, num_flows) + +if __name__ == "__main__": + main() diff --git a/flow-Agent/rag/README.md b/flow-Agent/rag/README.md new file mode 100644 index 0000000..8a89046 --- /dev/null +++ b/flow-Agent/rag/README.md @@ -0,0 +1 @@ +Contains code and configuration files related to the RAG framework, which is used to implement the Retrieval-Augmented Generation process. diff --git a/flow-Agent/rag/__init__.py b/flow-Agent/rag/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flow-Agent/rag/_pycache_/README.md b/flow-Agent/rag/_pycache_/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flow-Agent/rag/_pycache_/README.md @@ -0,0 +1 @@ + diff --git a/flow-Agent/rag/_pycache_/__init__.cpython-38.pyc b/flow-Agent/rag/_pycache_/__init__.cpython-38.pyc new file mode 100644 index 0000000..1cfa011 Binary files /dev/null and b/flow-Agent/rag/_pycache_/__init__.cpython-38.pyc differ diff --git a/flow-Agent/rag/_pycache_/index.cpython-38.pyc b/flow-Agent/rag/_pycache_/index.cpython-38.pyc new file mode 100644 index 0000000..a9a2c3d Binary files /dev/null and b/flow-Agent/rag/_pycache_/index.cpython-38.pyc differ diff --git a/flow-Agent/rag/_pycache_/util.cpython-38.pyc b/flow-Agent/rag/_pycache_/util.cpython-38.pyc new file mode 100644 index 0000000..edd8048 Binary files /dev/null and b/flow-Agent/rag/_pycache_/util.cpython-38.pyc differ diff --git a/flow-Agent/rag/build_index.py b/flow-Agent/rag/build_index.py new file mode 100644 index 0000000..e69de29 diff --git a/flow-Agent/rag/index.py b/flow-Agent/rag/index.py new file mode 100644 index 0000000..8833b20 --- /dev/null +++ b/flow-Agent/rag/index.py @@ -0,0 +1,62 @@ +import os +import pickle +import numpy as np +import pandas as pd +from sentence_transformers import SentenceTransformer +from .util import load_multiple_qa_files, prepareDocuments + +# 数据与模型路径 +BASE_DIR = os.path.dirname(__file__) +DATA_DIR = os.path.join(BASE_DIR, "..", "rag_date") +EMB_PATH = os.path.join(DATA_DIR, "embeddings.npy") +DOCS_PATH = os.path.join(DATA_DIR, "docs.pkl") + +# 默认模型路径(可修改) +DEFAULT_MODEL_PATH = "/mnt/c/Users/Public/OpenROAD-flow-scripts/orfs-agent/models/mxbai-embed-large-v1" + +# ============================================================ +# 🔹 构建并保存 Embedding 向量库 +# ============================================================ +def build_and_save_embeddings(base_dir="/mnt/e/OpenROAD-flow-scripts/orfs-agent/EDA-Corpus-main/Augmented_Data/Question-Answer", + model_name=DEFAULT_MODEL_PATH): + """ + 从 Flow / General / Tools 三个 CSV 构建向量库并保存。 + """ + print("[RAG] 正在加载 QA 文件...") + df = load_multiple_qa_files(base_dir) + + # 准备文档 + docs, docsDict = prepareDocuments(df) + + # 构建模型 + print(f"[RAG] 正在加载嵌入模型:{model_name}") + model = SentenceTransformer(model_name) + + # 生成向量 + print("[RAG] 正在生成文本向量...") + embeddings = model.encode(docs, convert_to_numpy=True, show_progress_bar=True) + + # 确保保存路径存在 + os.makedirs(DATA_DIR, exist_ok=True) + + # 保存 + np.save(EMB_PATH, embeddings) + with open(DOCS_PATH, "wb") as f: + pickle.dump((docs, docsDict), f) + + print(f"[RAG] ✅ 向量库构建完成并保存到 {DATA_DIR}") + + +# ============================================================ +# 🔹 加载已保存的向量库 +# ============================================================ +def load_embeddings_and_docs(): + if not os.path.exists(EMB_PATH) or not os.path.exists(DOCS_PATH): + raise FileNotFoundError("[RAG] 向量库文件不存在,请先运行 build_and_save_embeddings()") + + embeddings = np.load(EMB_PATH) + with open(DOCS_PATH, "rb") as f: + docs, docsDict = pickle.load(f) + + print(f"[RAG] 成功加载向量库,共 {len(docs)} 条文档。") + return embeddings, docs, docsDict \ No newline at end of file diff --git a/flow-Agent/rag/util.py b/flow-Agent/rag/util.py new file mode 100644 index 0000000..eaec640 --- /dev/null +++ b/flow-Agent/rag/util.py @@ -0,0 +1,277 @@ +import pandas as pd +import numpy as np +from sentence_transformers import SentenceTransformer, util as st_util +import os + +class modelUtility: + def __init__(self, modelName: str): + self.modelName = modelName + # ... 把你现有的 systemPrompt 和所有 ragPromptTemplate* 复制进来 ... + # (直接使用你之前提供的内容) + if modelName == "OpenROAD-Assistant/Script_Adaptor": + self.systemPrompt = """You are a tutor specializing in the knowledge of OpenROAD, the open-source EDA tool. You will be asked about general OpenROAD questions and OpenROAD Python API-related questions. +""" + else: + self.systemPrompt = """You are a OpenROAD Python code generator. You will generate the Python code to complete the task. Follow the following guidelines: +1. Only generate Python code, do not include any other text. +2. First generate ```python before the start of the Python code. +3. Generate ``` when finished the Python code. +4. If you don't know the answer, respond with: +```python +``` +""" + if "llama" not in modelName.lower() and "script_adaptor" not in modelName.lower() and "retrained" not in modelName.lower(): + self.ragPromptTemplateWithContext = """<|im_start|>system +{system_prompt}<|im_end|> +<|im_start|>user +Here are the OpenROAD APIs, You do not need to use them unless they are directly relevant to the answer: +===================== +{context} +===================== +Here is your task: +===================== +{question} +===================== + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|im_end|> +<|im_start|>assistant +""" + self.ragPromptTemplateWithoutContext = """<|im_start|>system +{system_prompt}<|im_end|> +<|im_start|>user +Here is your task: +===================== +{question} +===================== + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|im_end|> +<|im_start|>assistant +""" + self.ragWrongCodePromptTemplateWithContext = """<|im_start|>system +{system_prompt}<|im_end|> +<|im_start|>user +Here is your OpenROAD Python code generation task: +===================== +{question} +===================== + +Here is the wrong code you previously generated: +===================== +{wrongCode} +===================== + +I got the warning message when running the above wrong code: +===================== +{message} +===================== + +Here are some OpenROAD APIs, You do not need to use them unless they are directly relevant to the answer: +===================== +{context} +===================== + +The wrong code is not correct, please correct the wrong code or generate a new code to accomplish the OpenROAD Python code generation task. + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|im_end|> +<|im_start|>assistant +""" + self.ragWrongCodePromptTemplateWithoutContext = """<|im_start|>system +{system_prompt}<|im_end|> +<|im_start|>user +Here is your OpenROAD Python code generation task: +===================== +{question} +===================== + +Here is the wrong code you previously generated: +===================== +{wrongCode} +===================== + +I got the warning message when running the above wrong code: +===================== +{message} +===================== + +The wrong code is not correct, please correct the wrong code or generate a new code to accomplish the OpenROAD Python code generation task. + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|im_end|> +<|im_start|>assistant +""" + else: + self.ragPromptTemplateWithContext = """<|begin_of_text|><|start_header_id|>system<|end_header_id|> +{system_prompt}<|eot_id|> +<|start_header_id|>user<|end_header_id|> +Here are the OpenROAD APIs, You do not need to use them unless they are directly relevant to the answer: +===================== +{context} +===================== +Here is your task: +===================== +{question} +===================== + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|eot_id|> +<|start_header_id|>assistant<|end_header_id|> +""" + self.ragPromptTemplateWithoutContext = """<|begin_of_text|><|start_header_id|>system<|end_header_id|> +{system_prompt}<|eot_id|> +<|start_header_id|>user<|end_header_id|> +Here is your task: +===================== +{question} +===================== + +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|eot_id|> +<|start_header_id|>assistant<|end_header_id|> +""" + self.ragWrongCodePromptTemplateWithContext = """<|begin_of_text|><|start_header_id|>system<|end_header_id|> +{system_prompt}<|eot_id|> +<|start_header_id|>user<|end_header_id|> +Here is your OpenROAD Python code generation task: +===================== +{question} +===================== + +Here is the wrong code you previously generated: +===================== +{wrongCode} +===================== + +I got the warning message when running the above wrong code: +===================== +{message} +===================== + +Here are some OpenROAD APIs, You do not need to use them unless they are directly relevant to the answer: +===================== +{context} +===================== + +The wrong code is not correct, please correct the wrong code or generate a new code to accomplish the OpenROAD Python code generation task. +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|eot_id|> +<|start_header_id|>assistant<|end_header_id|> +""" + self.ragWrongCodePromptTemplateWithoutContext = """<|begin_of_text|><|start_header_id|>system<|end_header_id|> +{system_prompt}<|eot_id|> +<|start_header_id|>user<|end_header_id|> +Here is your OpenROAD Python code generation task: +===================== +{question} +===================== + +Here is the wrong code you previously generated: +===================== +{wrongCode} +===================== + +I got the warning message when running the above wrong code: +===================== +{message} +===================== + +The wrong code is not correct, please correct the wrong code or generate a new code to accomplish the OpenROAD Python code generation task. +If you define a function, you MUST actually call it in the code. +MUST NOT comment out the code that you write, especially the code you call the function.<|eot_id|> +<|start_header_id|>assistant<|end_header_id|> +""" + def isOpenROADAssistant(self): + return "OpenROAD-Assistant/Script_Adaptor" == self.modelName + +# ======================================================= +# 🔹 新增函数:支持从多个 QA 文件中加载合并数据 +# ======================================================= +def load_multiple_qa_files(base_dir): + """ + 从 base_dir 中读取 Flow.csv, General.csv, Tools.csv 三个文件并合并。 + """ + paths = [ + os.path.join(base_dir, "Flow", "Flow.csv"), + os.path.join(base_dir, "General", "General.csv"), + os.path.join(base_dir, "Tools", "Tools.csv"), + ] + + import glob + csv_paths = glob.glob(os.path.join(base_dir, "**", "*.csv"), recursive=True) + csv_paths = sorted(csv_paths) + if not csv_paths: + raise FileNotFoundError(f"[ERROR] No CSV files found under {base_dir}") + + + dfs = [] + total_rows_before = 0 + + for p in paths: + if os.path.exists(p): + try: + df = pd.read_csv(p) + dfs.append(df) + print(f"[INFO] Loaded {p} ({len(df)} rows)") + except Exception as e: + print(f"[WARN] Failed to read {p}: {e}") + else: + print(f"[WARN] File not found: {p}") + + if not dfs: + raise FileNotFoundError("[ERROR] No valid QA CSV files found in base_dir") + + df_all = pd.concat(dfs, ignore_index=True) + print(f"[INFO] Total rows before dedup: {total_rows_before}; concatenated: {len(df_all)}") + + # 不立即 drop_duplicates,先保存原始数,便于调试 + df_clean = df_all.drop_duplicates().fillna("") + print(f"[INFO] After drop_duplicates & fillna: {len(df_clean)} rows") + + return df_clean + + + +def prepareDocuments(df): + """ + 仅用于 QA 数据集。提取 Prompts 和 Answers 列,组合为文档。 + """ + documents = [] + documentsDict = {} + + if not {"Prompts", "Answers"}.issubset(df.columns): + raise ValueError("[ERROR] The input DataFrame must contain 'Prompts' and 'Answers' columns.") + + for _, row in df.iterrows(): + q, a = str(row["Prompts"]).strip(), str(row["Answers"]).strip() + if not q or not a: + continue + content = f"Q: {q}\nA: {a}" + documents.append(content) + documentsDict[content] = {"Prompts": q, "Answers": a} + + print(f"[INFO] Prepared {len(documents)} QA documents for embedding.") + return documents, documentsDict + + + +def answerWithRAG(question, embeddings, embeddingModel, allSplits, allDict, topk=10, score_threshold=0.4): + q_emb = embeddingModel.encode(question, convert_to_tensor=True).cpu() + # embeddings is a tensor (convert_to_tensor=True recommended) + scores = st_util.cos_sim(q_emb, embeddings.cpu()) # shape (1, N) + np_scores = scores.cpu().numpy().flatten() + top_idx = np.argsort(np_scores)[-topk:][::-1] + relevantDocs = [] + for idx in top_idx: + print(f"[DEBUG] RAG candidate {idx} score={np_scores[idx]:.3f}") + if np_scores[idx] < score_threshold: + break + relevantDocs.append(allSplits[idx]) + finalDocs = [] + for doc in relevantDocs: + finalDocs.append("\n".join(f"# {k} {v}" for k, v in allDict[doc].items())) + context = "" + if finalDocs: + context = "\n\n".join(finalDocs) + return context \ No newline at end of file diff --git a/flow-Agent/rag_data/RAGAPIs.csv b/flow-Agent/rag_data/RAGAPIs.csv new file mode 100644 index 0000000..0f995a1 --- /dev/null +++ b/flow-Agent/rag_data/RAGAPIs.csv @@ -0,0 +1,193 @@ +Description:,Function Name:,Parameters:,Return Type: +Get the openroad.Tech object,openroad.Tech(),,openroad.Tech +Read .lib files,openroad.Tech.readLiberty(,str(file_name), +Read .lef files,openroad.Tech.readLef(,str(file_name), +Get the openroad db via openroad.Tech object,openroad.Tech.getDB(),,odb.dbDatabase +Get the openroad.Design object,openroad.Design(,openroad.Tech,openroad.Design +Get the I/O pin placer,openroad.Design.getIOPlacer(),,ppl.IOPlacer +Use the name of the layer to get the odb.dbTechLayer object,openroad.Design.getTech().getDB().getTech().findLayer(,str(layer_name),odb.dbTechLayer +Get the parameters of the IO pin placer,ppl.IOPlacer.getParameters(,,ppl.Parameters +Set the minimum distance between each pin of the IO pin placer,ppl.Parameters.setMinDistance(,int(min_dist), +Get the setting of the minimum distance between each pin of the IO pin placer,ppl.Parameters.getMinDistance(),,int +"Set the unit for calling ppl.Parameters.setMinDistance(int) in ""number of tracks"" or in openroad's unit of the IO pin placer",ppl.Parameters.setMinDistanceInTracks(,bool(in_track), +"Check if the unit fot calling ppl.Parameters.setMinDistance(int) of the IO pin placer is in ""number of tracks"" or in openroad's unit, return True if is in ""number of tracks”",ppl.Parameters.getMinDistanceInTracks(),,bool +Get the floorplanner,openroad.Design.getFloorplan(),,ifp.InitFloorplan +"get the minimum placing unit of the design, the input is the name of the site desifned in the technology file",ifp.InitFloorplan.findSite(,str(site),odb.dbSite +"Create tracks, must call this after floorplanning",ifp.InitFloorplan.makeTracks(),, +"Perform floorplanning, utilization is in [0, 100]%. The base_site determines the single-height rows. For hybrid rows it is a site containing a row pattern.",ifp.InitFloorplan.initFloorplan(,"float(utilization), float(aspect_ratio), int(core_space_bottom), int(core_space_top), int(core_space_left), int(core_space_right), odb.dbSite", +"Perform floorplanning, the base_site determines the single-height rows. For hybrid rows it is a site containing a row pattern.",ifp.InitFloorplan.initFloorplan(,"odb.Rect(die), odb.Rect(core), odb.dbSite(base_site)", +Create an openroad.odb.Rect object,odb.Rect(,"int(x1), int(y1), int(x2), int(y2)",odb.Rect +Similar to openroad.get_db_block,openroad.Design.getBlock(),,odb.dbBlock +Get the name of the pin,openroad.Design.getITermName(,odb.dbITerm(),str +Check if a instance is a part of clock nets,openroad.Design.isInClock(,odb.dbInst(),bool +Read the Verilog files into OpenROAD,openroad.Design.readVerilog(,str(file_name), +Read the design file in DEF format (containing placement and routing information),openroad.Design.readDef(,str(file_name), +Find the top module of the Verilog file and connect all other modules. The Verilog files must be read into OpenROAD first.,openroad.Design.link(,str(design_name), +Read the design file written in OpenROAD database format,openroad.Design.readDb(,str(file_name), +Write the design file in OpenROAD database format,openroad.Design.writeDb(,str(file_name), +Change the unit from micron (um) to the unit used in OpenROAD,openroad.Design.micronToDBU(,float(coord),int +Similar to openroad.get_db_tech(),openroad.Design.getTech(),,openroad.Tech +Check is a library cell (master cell) is a buffer,openroad.Design.isBuffer(,odb.dbMaster(),bool +Check if a library cell (master cell) is an inverter,openroad.Design.isInverter(,odb.dbMaster(),bool +Check if a library cell (master cell) is a flip-flop,openroad.Design.isSequential(,odb.dbMaster(),bool +Check if a pin is connected to VDD or VSS net,openroad.Design.isInSupply(,odb.dbITerm(),bool +Get the actual physical wirelength of a routed net,openroad.Design.getNetRoutedLength(,odb.dbNet(),int +"Write DEF file, str is the name of the file",openroad.Design.writeDef(,str(file_name), +Get the openroad.Timing object,openroad.Timing(,openroad.Design,openroad.Timing +Get the sum of switching and internal power of an instance,openroad.Timing.dynamicPower(,"odb.dbInst(), openroad.Timing.getCorners()[int(index)]",float +Get the sum of wire capacitance and pin capacitance of a Net,openroad.Timing.getNetCap(,"odb.dbNet(), openroad.Timing.getCOrners()[int(index)], openroad.Timing.Max",float +Get the sum of wire capacitance and pin capacitance of a Net,openroad.Timing.getNetCap(,"odb.dbNet(), openroad.Timing.getCOrners()[int(index)], openroad.Timing.Min",float +Get the maximum rising arrival time of a pin across all corners,openroad.Timing.getPinArrival(,"odb.dbITerm(), openroad.Timing.Rise, openroad.Timing.Max",float +Get the minimum rising arrival time of a pin across all corners,openroad.Timing.getPinArrival(,"odb.dbITerm(), openroad.Timing.Rise, openroad.Timing.Min",float +Get the maximum falling arrival time of a pin across all corners,openroad.Timing.getPinArrival(,"odb.dbITerm(), openroad.Timing.Fall, openroad.Timing.Max",float +Get the minimum falling arrival time of a pin across all corners,openroad.Timing.getPinArrival(,"odb.dbITerm(), openroad.Timing.Fall, openroad.Timing.Min",float +Get the maximum rising arrival time of a port across all corners,openroad.Timing.getPinArrival(,"odb.dbBTerm(), openroad.Timing.Rise, openroad.Timing.Max",float +Get the minimum rising arrival time of a port across all corners,openroad.Timing.getPinArrival(,"odb.dbBTerm(), openroad.Timing.Rise, openroad.Timing.Min",float +Get the maximum falling arrival time of a port across all corners,openroad.Timing.getPinArrival(,"odb.dbBTerm(), openroad.Timing.Fall, openroad.Timing.Max",float +Get the minimum falling arrival time of a port across all corners,openroad.Timing.getPinArrival(,"odb.dbBTerm(), openroad.Timing.Fall, openroad.Timing.Min",float +Get the maximum rising slack of a pin across all corners ,openroad.Timing.getPinSlack(,"odb.dbITerm(), openroad.Timing.Rise, openroad.Timing.Max",float +Get the minimum rising slack of a pin across all corners ,openroad.Timing.getPinSlack(,"odb.dbITerm(), openroad.Timing.iming.Rise, openroad.Timing.Min",float +Get the maximum falling slack of a pin across all corners ,openroad.Timing.getPinSlack(,"odb.dbITerm(), openroad.Timing.Fall, openroad.Timing.Max",float +Get the minimum falling slack of a pin across all corners ,openroad.Timing.getPinSlack(,"odb.dbITerm(), openroad.Timing.Fall, openroad.Timing.Min",float +Get the maximum rising slack of a port across all corners ,openroad.Timing.getPinSlack(,"odb.dbBTerm(), openroad.Timing.Rise, openroad.Timing.Max",float +Get the minimum rising slack of a port across all corners ,openroad.Timing.getPinSlack(,"odb.dbBTerm(), openroad.Timing.Rise, openroad.Timing.Min",float +Get the maximum falling slack of a port across all corners ,openroad.Timing.getPinSlack(,"odb.dbBTerm(), openroad.Timing.Fall, openroad.Timing.Max",float +Get the minimum falling slack of a port across all corners ,openroad.Timing.getPinSlack(,"odb.dbBTerm(), openroad.Timing.Fall, openroad.Timing.Min",float +Get the minimum slew of the pin across all corners,openroad.Timing.getPinSlew(,"odb.dbITerm, openroad.Timing.Min",float +Get the maximum slew of the pin across all corners,openroad.Timing.getPinSlew(,"odb.dbITerm, openroad.Timing.Max",float +Get the minimum slew of the port across all corners,openroad.Timing.getPinSlew(,"odb.dbBTerm, openroad.Timing.Min",float +Get the maximum slew of the port across all corners,openroad.Timing.getPinSlew(,"odb.dbBTerm, openroad.Timing.Max",float +Get the maximum input capacitance of a pin,openroad.Timing.getPortCap(,"odb.ITerm, openroad.Timing.getCorners()[int(index)], openroad.Timing.Max",float +Get the minimum input capacitance of a pin,openroad.Timing.getPortCap(,"odb.ITerm, openroad.Timing.getCorners()[int(index)], openroad.Timing.Min",float +Check if the pin is the end point of a timing path,openroad.Timing.isEndpoint(,odb.ITerm(),bool +Check if the port is the end point of a timing path,openroad.Timing.isEndpoint(,odb.BTerm(),bool +"Check if the number is ""inf""",openroad.Timing.isTimeInf(,float(time),bool +Get the instance's leakage power,openroad.Timing.staticPower(,"odb.dbInst, openroad.Timing.getCorners()[int(index)]",float +Get the global placer,openroad.Design.getReplace(),,gpl.Replace +"Perform global placement (don't call this function if ""gpl.Replace.doInitialPlace()"" or ""gpl.Replace.doNesterovPlace()"" is called)",gpl.Replace.doIncrementalPlace(,int(thread), +"Perform global placement (don't call this function if ""gpl.Replace.doIncrementalPlace()"" is called)",gpl.Replace.doInitialPlace(),, +"Use ""electrostatic force equations"" to perform global placement (don't call this function if ""gpl.Replace.doIncrementalPlace()"" is called)",gpl.Replace.doNesterovPlace(,int(thread),int +Get the macro placer,openroad.Design.getMacroPlacer(),,mpl.MacroPlacer +"Run macro placement and push all macros to the design boundary, must be called after global placement",mpl.MacroPlacer.placeMacrosCornerMaxWl(),, +"Run macro placement and place all macros together, must be called after global placement",mpl.MacroPlacer.placeMacrosCornerMinWL(),, +Snap the macro to a layer,mpl.MacroPlacer.setSnapLayer(,odb.dbTechLayer, +Set the fence region as a user defined area in microns,mpl.MacroPlacer.setFenceRegion(,"float(lx), doubl(ly), float(ux), float(uy)", +Set the channel width between macros,mpl.MacroPlacer.setChannel(,"float(channel_x), float(channel_y)", +Set the halo around macros,mpl.MacroPlacer.setHalo(,"float(halo_x), float(halo_y)", +Get the openroad db,openroad.get_db(),,odb.dbDatabase +Getting openroad.Tech object via openroad.Design object. Similar to openroad.Design.getTech(),openroad.get_db_tech(),,odb.dbTech +Similar to openroad.Design.getBlock,openroad.get_db_block(),,odb.dbBlock +"Get the detailed placer, or called as legalizer",openroad.Design.getOpendp(),,dpl.Opendp +"Perform legalization, max_displacment is in sites. use zero for defaults.",dpl.Opendp.detailedPlacement(,"int(max_displacement_x), int(max_displacement_y), str(report_file_name), bool(disallow_one_site_gaps)", +Get legalization report,dpl.Opendp.reportLegalizationStats(),, +Check legalization result,dpl.Opendp.checkPlacement(,"bool(verbose), bool(disallow_one_site_gaps), str(report_file_name)", +"Place filler cells after legalization, prefix is the naming pattern of the filler cells",dpl.Opendp.fillerPlacement(,"list(odn.dbMaster), str(prefix)", +Remove filler cells,dpl.Opendp.removeFillers(),, +"Propagate the clock signal, openroad.Design.evalTclString(“create_clock -period 20 [get_ports clk] -name core_clock”) must be celled before this.","openroad.Design.evalTclString(""set_propagated_clock [core_clock]"")",, +Set the unit resistance value and unit capacitance value of the clock net,"openroad.Design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"")",, +Set the unit resistance value and unit capacitance value of regular signal net,"openroad.Design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"")",, +Get the module to perform CTS (clock tree synthesis),openroad.Design.getTritonCts(),,cts.TritonCTS +Run CTS (clock tree synthesis),cts.TritonCTS.runTritonCts(,, +Report the CTS result,cts.TritonCTS.reportCtsMetrics(,, +Get the parameter seeting of the CTS module,cts.TritonCTS.getParms(,,cts.CtsOptions +Get the character setting of the CTS module,cts.TritonCTS.getCharacterization(,,cts.TechChar +"Set the clock net by the name, return 0 if complete normally, return 1 if cannot find the clock net with the name",cts.TritonCTS.setClockNets(,str(name), +Set the available clock buffer library cells with he name,cts.TritonCTS.setBufferList(,str(buffers), +Set the rooting clock buffer (starting point) with the name,cts.TritonCTS.setRootBuffer(,str(buffers), +Set the sinking clock buffer (end point) with the name,cts.TritonCTS.setSinkBuffer(,str(buffers), +Set the reference unit for sgmenting the wire,cts.CtsOptions.setWireSegmentUnit(,, +"Get the PDN (power grid, or called power delivery network) generator",openroad.Design.getPdnGen(,,pdn.PdnGen +Get the report of current PDN generation,pdn.PdnGen.report(,, +Get all voltage domain of the design,pdn.PdnGen.getDomains(,,list(pdn.VoltageDomain) +Find the voltage domain with the name of the domain,pdn.PdnGen.findDoamin(,str(name),pdn.VoltageDomain +"Set the voltage domain of the design core, power means the ower net, ground means the ground net",pdn.PdnGen.setCoreDomain(,"odb.dbNet(power), odb.dbNet(switched_power), odb.dbNet(ground), list(odb.dbNet)", +"Build the PDN, if ""trim"" is True, then will clean up some vias and trim the shape of smoe wires. If ""trim"" is set to False, then the PDN will remain the same",pdn.PdnGen.buildGrids(,bool(trim), +Find the high level PDN grid with the name,pdn.PdnGen.findGrid(,str(name), +"Create the high level PDN grid for the macro. ""domain"" is the voltage domain. ""name"" will be the name of this PDN grid. ""starts_with"" can be one of ""pdn.GRID, pdn.POWER, or pdn.GROUND"". ""inst"" is the target macro. ""halo"" is the halo set around the macro. ""pg_pins_to_boundary"" is set to True if the VDD and VSS pins of the macro is set to be around the macro, is is set to False, then VDD and VSS pins will appear within the macro block.",pdn.PdnGen.makeInstanceGrid(,"pdn.VoltageDomain(domain), str(name), pdn.StartsWith(starts_with), odb.dbInst(inst), list(int(halo)), bool(pg_pins_to_boundary), bool(default_grid), list(odb.dbTechLayer(generate_obstructions)), bool(is_bump)", +"Create the PDN ring around the design or the macro. ""grid"" is the high level PDN grid. ""layer0"" and ""layer1"" are the two layers to place the metal stripes of the PDN ring. ""width0"" and ""spacing0"" are the settings of ""layer0"". ""width1"" and ""spacing1"" are the two settings of ""layer1"". ""starts_with"" can be one of ""pdn.GRID, pdn.POWER, or pdn.GROUND"". ""offset"" is the offset setting of the PDN ring. ""pad_offset"" is the offset of padding of the PDN ring. ""extend"" is set to False then the PDN ring will remain the same, if set to True, then it will extend to the boundary. ""pad_pin_layers"" is a list of layers that will connect to pad. ""nets"" can be an empty list.",pdn.PdnGen.makeRing(,"pdn.Grid(grid), odb.dbTechLayer(layer0), int(width0),int(spacing0), odb.dbTechLayer(layer1), int(width1), int(spacing1), pdn.StartsWith(starts_with), list(int(offset)), list(int(pad_offset)), bool(extend), list(odb.dbTechLayer(pad_pin_layers), list(odb.dbNet(nets)", +"Create the PDN stripes at the lowest metal layer and following the pin pattern of the cells. ""extend"" can be either of ""pdn.CORE, pdn.RINGS, pdn.BOUNDARY, or pdn. FIXED"". ""layer"" is the metal layer place the PDN stripes. ""width"" specifies the metal stripe width. ""grid"" is the high level PDN grid.",pdn.PdnGen.makeFollowpin(,"pdn.Grid(grid), odb.dbTechLayer(layer), int(width), pdn.ExtensionMode(extend)", +"Create the PDN stripes generating pattern. ""grid"" is the high level PDN grid. ""layer"" specifies the metal layer. ""starts_with"" can be one of ""pdn.GRID, pdn.POWER, or pdn.GROUND"". ""extend"" can be either of ""pdn.CORE, pdn.RINGS, pdn.BOUNDARY, or pdn. FIXED"". The rest are the settings of the physical dimension of the metal stripes.",pdn.PdnGen.makeStrap(,"pdn.Grid(grid), odb.dbTechLayer(layer), int(width), int(spacing), int(pitch), int(offset), int(number_of_straps), bool(snap), pdn.StartsWith(starts_with), pdn.ExtensionMode(extend), list(odb.dbNet(nets))", +"Connect the stripes between two metal layers (creating vias). ""grid"" is the high level PDN grid. ""layer0"" and ""layer1"" specify the two metal layers. ""cut_pitch_x"" and ""cut_pitch_y"" specify the cut via generating pattern. ""vias"" is a list of vis generating rules defined in the technology file. ""max_rows"" and ""max_columns"" are the settings of the numbers of rows and columns. The key and value of ""dict()"" are odb.dbTechLayer and int. ""dont_use_vias"" is the name of the name of the vis generating rule you do not want to use.",pdn.PdnGen.makeConnect(,"pdn.Grid(grid), odb.dbTechLayer(layer0), odb.dbTechLayer(layer1), int(cut_pitch_x), int(cut_pitch_y), list(odb.dbTechViaGenerateRule(vias)), list(odb.dbTechVia(techvias), int(max_rows), int(max_columns), list(odb.dbTechLayer(ongrid)), dict(), str(dont_use_vias)", +Rip up the selected VDD/VSS net,pdn.PdnGen.ripUp(,(odb.dbNet net), +Check the PDN setup at the end of all pattern are defined,pdn.PdnGen.checkSetup(,, +"Write the PDN generation result to OpenROAD database. Usually set ""add_pins"" to True. ""report_file"" specifies the name of the report file.",pdn.PdnGen.writeToDb(,"bool(add_pins), str(report_file)", +Get the PDN analysis tool,openroad.Design.getPDNSim(),, +Specifies the target VDD/VSS net,psm.PDNSim.setNet(,odb.dbNet(net), +"Analyze the PDN, if set all files to enpty strings and set ""enable_em"" to False, PDNSim will use the default setting.",psm.PDNSim.analyzePowerGrid(,"str(voltage_file), bool(enable_em), str(em_file), str(error_file)", +"Perform IR drop analysis, ""layer"" specifies the layer.",psm.PDNSim.getIRDropForLayer(,odb.dbTechLayer(layer), +Set the corner information for the PDN analysis tool.,"openroad.Design.evalTclString(f""psm::set_corner [sta::cmd_corner]"")",, +Get the global router.,openroad.Design.getGlobalRouter(),,grt.GlobalRouter +Set the lowest routing layer,grt.GlobalRouter.setMinRoutingLayer(,int(min_layer), +Set the highest routing layer,grt.GlobalRouter.setMaxRoutingLayer(,int(max_layer), +Set the lowest routing layer for clock net,grt.GlobalRouter.setMinLayerForClock(,int(min_layer), +Set the highest routing layer for clock net,grt.GlobalRouter.setMaxLayerForClock(,int(max_layer), +Set the iteration to run if facing overflow in some gcells,grt.GlobalRouter.setOverflowIterations(,int(iterations), +"Run global routing, all default values are False.",grt.GlobalRouter.globalRoute(,"bool(save_guides), bool(start_incremental), bool(end_incremental)", +Get the detailed router,openroad.Design.getTritonRoute(),,drt.TritonRoute +Run detailed routing.,drt.TritonRoute.main(),, +Get the amount of DRVs,drt.getNumDRVs(),,int +Get the parameter settings of the detailed router.,drt.ParamStruct(),,drt.ParamStruct +Number of iteraion of detailed routing. Assign an integer to this variable,drt.ParamStruct.drouteEndIter(),, +Assign boolean to this variable to enable via generating during detailed routing,drt.ParamStruct.enableViaGen(),, +Find the instance using the name of that instance,odb.dbBlock.findInst(,str(name),odb.dbInst +Get a list of all nets,odb.dbBlock.getNets(),,list(odb.dbNet) +Get a list of all I/O ports,odb.dbBlock.getBTerms(),,list(odb.dbBTerm) +Find the I/O port using the name of that I/O port,odb.dbBlock.findBTerm(,str(name),odb.dbBTerm +Get a list of all pins,odb.dbBlock.getITerms(),,list(odb.dbITerm) +Find the pin using the name of that pin,odb.dbBlock.findITerm(,str(name),odb.dbITerm +Get a list of all instances,odb.dbBlock.getInsts(),,list(odb.dbInst) +Get db unit per micron (um),odb.dbBlock.getDbUnitsPerMicron(),,int +Get the core rectangle,odb.dbBlock.getCoreArea(),,odb.Rect +Get a list of all rows in the design,odb.dbBlock.getRows(),,list(odb.dbRow) +Get the site used in this row,odb.dbRow.getSite(),,odb.dbSite +Get the bottom left x location of this rectangle,odb.Rect.xMin(),,int +Get the bottom left y location of this rectangle,odb.Rect.yMin(),,int +Get the top right x location of this rectangle,odb.Rect.xMax(),,int +Get the top right y location of this rectangle,odb.Rect.yMax(),,int +Connect pins with nets. odb.dbBlock.addGlobalConnect should be executed before calling this function,odb.dbBlock.globalConnect(),, +"Given the pattern of the instance names, connect the net to the pins of instances that match the pin pattern",odb.dbBlock.addGlobalConnect(,"odb.dbRegion(region), str(instPattern), str(pinPattern), odb.dbNet(net), bool(do_connect)", +Getting openroad.Tech object via openroad.odb.dbBlock object. Similar to openroad.Design.getTech(),odb.dbBlock.getTech(),,odb.dbTech +"Return True if the net is marked as selected, return False if the net is not marked as selected.",odb.dbNet.isSelect(),,bool +Get the name of the net,odb.dbNet.getName(),,str +"Set the wire type of the net. Input can only be one of the followings: (""NONE"", ""COVER"", ""FIXED"", ""ROUTED"", ""SHIELD"", “NOSHIELD"")",odb.dbNet.setWireType(,str, +"Get the odb.dbWireType object in string. Return value can be one of the followings: (""NONE"", ""COVER"", ""FIXED"", ""ROUTED"", ""SHIELD"", ""NOSHIELD"")",odb.dbNet.getWireType(,,str +Get the total coupling capacitance of the net,odb.dbNet.getTotalCouplingCap(),,float +Get the total capacitance of the net,odb.dbNet.getTotalCapacitance(),,float +Get the total resistance of the net,odb.dbNet.getTotalResistance(),,float +Get all pins of the net,odb.dbNet.getITerms(),,list(odb.dbITerm) +Get all pins of the instance,odb.dbInst.getITerms(),,list(odb.dbITerm) +Get the name of the instance,odb.dbInst.getName(),,str +Get the x y location as a odb.Point object of the instance. Similar to odb.dbInst.getLocation(),odb.dbInst.getOrigin(),,odb.Point +Get the x location of the odb.Point object,odb.Point.getX(),,int +Get the y location of the odb.Point object,odb.Point.getY(),,int +Set the x y location of the instance. Similar to odb.dbInst.setLocation(),odb.dbInst.setOrigin(,"int(x), int(y)", +Get the x and y location as a odb.Point object of the instance. Similar to odb.dbInst.getOrigin(),odb.dbInst.getLocation(),,odb.Point +Set the x and y location of the instance. Similar to odb.dbInst.setOrigin(),odb.dbInst.setLocation(,"int(x), int(y)", +"Get the placement status of the instance. Status can only be one of the followings: (""NONE"", ""UNPLACED"", ""SUGGESTED"", ""PLACED"", ""LOCKED"", ""FIRM"", “COVER"")",odb.dbInst.getPlacementStatus(),,str +"Set the placement status of the instance. Status can only be one of the followings: (""NONE"", ""UNPLACED"", ""SUGGESTED"", ""PLACED"", ""LOCKED"", ""FIRM"", “COVER"")",odb.dbInst.setPlacementStatus(,str, +"Get the rotation (orientation) as a string of the instance. Orient can only be one of the followings: (""R0"", ""R90"", ""R180"", ""R270"", ""MY"", ""MYR90"", ""MX"", “MXR90"")",odb.dbInst.getOrient(),,str +"Set the rotation (orientation) of the instance. Orient can only be one of the followings: (""R0"", ""R90"", ""R180"", ""R270"", ""MY"", ""MYR90"", ""MX"", “MXR90"")",odb.dbInst.setOrient(,str, +Get the dbTransform object of the instance.,odb.dbInst.getTransform(),,odb.dbTransform +Set the dbTransform object of the instance.,odb.dbInst.setTransform(,odb.dbTransform(transform), +"Get the orientation (rotation) of the transform object, odb.dbInst.getTransform() function must be called before calling this function.",odb.dbTransform.getOrient(),,odb.dbOrientType +"Get the x and y location of the transform object, odb.dbInst.getTransform() function must be called before calling this function.",odb.dbTransform.getOffset(),,odb.Point +"Update the orientation (rotation) of the transform object, odb.dbInst.getTransform() function must be called before calling this function.",odb.dbTransform.setOrient(,str, +"Update the x and y location of the transform object, odb.dbInst.getTransform() function must be called before calling this function.",odb.dbTransform.setOffset(,odb.Point(point), +"Update the x and y location and the orientation (rotation) of the transform object, odb.dbInst.getTransform() function must be called before calling this function.",odb.dbTransform.setTransform(,"str, odb.Point", +Invert the x and y location and the rotation (orientation) of the transform,odb.dbTransform.invert(),, +Set the x and y location of the point object,odb.Point(,"int(x), int(y)",odb.Point +"v=True to set the instance as a ""do not touch” or “don’t touch” type instance. Use v=False to reset the ""do not touch"" setting.",odb.dbInst.setDoNotTouch(,bool(v), +"Return True if the instance is set as ""do not touch"" instance, return False if the instance is not set as ""do not touch"" instance",odb.dbInst.isDoNotTouch(),,bool +Return True if the instance is placed.,odb.dbInst.isPlaced(),,bool +Get the net connected to this pin,odb.dbITerm.getNet(),,odb.dbNet +Return True if the pin is an output pin of the instance. Return False if the pin is not an output pin of the instance.,odb.dbITerm.isOutputSignal(),,bool +Return True if the pin is an input pin of the instance. Return False if the pin is not an input pin of the instance.,odb.dbITerm.isInputSignal(),,bool +"Get the signal type of the net. Return ""POWER"" if the net is a power (VDD) net. Return ""GROUND"" is the net is a ground (VSS) net.",odb.dbNet.getSigType(),,str +"Set the signal type of the net. Set type to ""POWER"" if the net is a power (VDD) net. Set type to ""GROUND"" is the net is a ground (VSS) net.",odb.dbNet.setSigType(,str(type), +Get the cut layer class rule of the technology layer,odb.dbTechLayer.getTechLayerCutClassRules(,,list(odb.dbTechLayerCutClassRule) +Upsize or downsize the instance with the input “master” library cell,odb.dbInst.swapMaster(,odb.dbMaster(master), +Use name to find the master cell (library cell). Return None if the name does not match any master cell.,odb.dbDatabase.findMaster(,str(name),odb.dbMaster +Create a clock signal at the clk_i port with a period of 50 ps and name it core_clk.,openroad.Design.evalTclString(“create_clock -period 50 [get_ports clk_i] -name core_clock”),, +"Return True if the net’s disconnected flag is set to True, which typically means the net is disconnected from all pins. Return False if the flag is set to False, indicating that the net has connections with pins.",odb.dbNet.isDisconnected(),,Bool +Print opcodes and data of its wire,odb.dbNet.printWire(),, +"Return True if the master is a filler cell, return False if the master is not a filler cell.",odb.dbMaster.isFiller(),,bool \ No newline at end of file diff --git a/flow-Agent/rag_data/RAGCodePiece.csv b/flow-Agent/rag_data/RAGCodePiece.csv new file mode 100644 index 0000000..fa454ad --- /dev/null +++ b/flow-Agent/rag_data/RAGCodePiece.csv @@ -0,0 +1,658 @@ +Description:,Code Piece: +Template of reading .lib (liberty) files,"from openroad import Tech +from pathlib import Path + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +libDir = Path(""../Design/nangate45/lib"") + +# Read all liberty file from the library directories +libFiles = libDir.glob(""*.lib"") + +# Load liberty timing libraries +for libFile in libFiles: + tech.readLiberty(libFile.as_posix())" +Template of reading .lef files,"from openroad import Tech +from pathlib import Path + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +lefDir = Path(""../Design/nangate45/lef"") +techlefDir = Path(""../Design/nangate45/lef"") + +# Read all LEF files from the library directories +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') + +# Load technology and cell LEF files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix())" +Template of reading technology files,"from openroad import Tech +from pathlib import Path + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +techlefDir = Path(""../Design/nangate45/lef"") + +# Read all tech led files from the library directories +techLefFiles = lefDir.glob(""*.tech.lef"") + +# Load technology and cell LEF files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix())" +Template of reading verilog files (reading netlist file),"from openroad import Tech, Design +from pathlib import Path + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +libDir = Path(""../Design/nangate45/lib"") +lefDir = Path(""../Design/nangate45/lef"") +techlefDir = Path(""../Design/nangate45/lef"") +designDir = Path(""../Design/"") + +design_name = ""1_synth"" +design_top_module_name = ""gcd"" + +# Read all liberty (.lib) and LEF files from the library directories +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') + +# Load liberty timing libraries +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +# Load technology and cell LEF files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) + +# Create design and read Verilog netlist +design = Design(tech) +verilogFile = designDir/str(design_name + "".v"") +design.readVerilog(verilogFile.as_posix()) +design.link(design_top_module_name)" +Template of reading OpenROAD design file in .odb format,"from openroad import Tech, Design + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +libDir = Path(""../Design/nangate45/lib"") +lefDir = Path(""../Design/nangate45/lef"") +techlefDir = Path(""../Design/nangate45/lef"") +designDir = Path(""../Design/"") + +design_name = ""1_synth"" +design_top_module_name = ""gcd"" + +# Read all liberty (.lib) and LEF files from the library directories +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') + +# Load liberty timing libraries +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +# Load technology and cell LEF files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) + +# Create design and read ode file +design = Design(tech) +odbFile = designDir/str(design_name + "".odb"") +design.readDb(odbFile.as_posix())" +Template of reading DEF (.def) files,"from openroad import Tech, Design + +# Initialize OpenROAD objects and read technology files +tech = Tech() +# Set paths to library and design files +libDir = Path(""../Design/nangate45/lib"") +lefDir = Path(""../Design/nangate45/lef"") +techlefDir = Path(""../Design/nangate45/lef"") +designDir = Path(""../Design/"") + +design_name = ""1_synth"" +design_top_module_name = ""gcd"" + +# Read all liberty (.lib) and LEF files from the library directories +libFiles = libDir.glob(""*.lib"") +techLefFiles = lefDir.glob(""*.tech.lef"") +lefFiles = lefDir.glob('*.lef') + +# Load liberty timing libraries +for libFile in libFiles: + tech.readLiberty(libFile.as_posix()) +# Load technology and cell LEF files +for techLefFile in techLefFiles: + tech.readLef(techLefFile.as_posix()) +for lefFile in lefFiles: + tech.readLef(lefFile.as_posix()) + +# Create design and read def file +design = Design(tech) +defFile = designDir/str(design_name + "".def"") +design.readDef(defFile.as_posix())" +Template of creating and propagate the clock signal,"clock_period = 200 +port_name = ""port_name"" +clock_name = ""clock_name"" +# Create clock signal +design.evalTclString(""create_clock -period %s [get_ports %s] -name %s""%(clock_period, port_name, clock_name)) +# Propagate the clock signal +design.evalTclString(""set_propagated_clock [all_clocks]"")" +Template of running floorplanning with utilization rate (hight/width),"# Initialize floorplan with core and die area +floorplan = design.getFloorplan() +# Set die area to 60um x 50um +# Initialize floorplan with FreePDK45 site +site = floorplan.findSite(""FreePDK45_38x28_10R_NP_162NW_34O"") +utilization = 0.5 +aspect_ratio = 1.0 +leftSpace = design.micronToDBU(10) +rightSpace = design.micronToDBU(10) +topSpace = design.micronToDBU(10) +bottomSpace = design.micronToDBU(10) +floorplan.initFloorplan(utilization, aspect_ratio, bottomSpace, topSpace, leftSpace, rightSpace, site) +floorplan.makeTracks()" +Template of running floorplanning with specific die and core area,"import odb +# Initialize floorplan with core and die area +floorplan = design.getFloorplan() +# Set die area to 60um x 50um +die_area = odb.Rect(design.micronToDBU(0), design.micronToDBU(0), + design.micronToDBU(60), design.micronToDBU(50)) +# Set core area to 50um x 40um with 5um margins +core_area = odb.Rect(design.micronToDBU(5), design.micronToDBU(5), + design.micronToDBU(55), design.micronToDBU(45)) +# Initialize floorplan with FreePDK45 site +site = floorplan.findSite(""FreePDK45_38x28_10R_NP_162NW_34O"") +floorplan.initFloorplan(die_area, core_area, site) +floorplan.makeTracks()" +Template of placing I/O pins (ports),"# Configure and run I/O pin placement +params = design.getIOPlacer().getParameters() +params.setRandSeed(42) +params.setMinDistanceInTracks(False) +params.setMinDistance(design.micronToDBU(0)) +params.setCornerAvoidance(design.micronToDBU(0)) +# Place I/O pins on metal8 (horizontal) and metal9 (vertical) layers +design.getIOPlacer().addHorLayer(design.getTech().getDB().getTech().findLayer(""metal8"")) +design.getIOPlacer().addVerLayer(design.getTech().getDB().getTech().findLayer(""metal9"")) +IOPlacer_random_mode = True +design.getIOPlacer().runAnnealing(IOPlacer_random_mode)" +Template of running global placement,"# Configure and run global placement +gpl = design.getReplace() +gpl.setTimingDrivenMode(False) +gpl.setRoutabilityDrivenMode(True) +gpl.setUniformTargetDensityMode(True) +# Limit initial placement iterations and set density penalty +gpl.setInitialPlaceMaxIter(10) +gpl.setInitDensityPenalityFactor(0.05) +gpl.doInitialPlace(threads = 4) +gpl.doNesterovPlace(threads = 4) +gpl.reset()" +Template of running macro placer,"# Place macro blocks if present +macros = [inst for inst in design.getBlock().getInsts() if inst.getMaster().isBlock()] +if len(macros) > 0: + mpl = design.getMacroPlacer() + block = design.getBlock() + core = block.getCoreArea() + mpl.place( + num_threads = 64, + max_num_macro = len(macros)//8, + min_num_macro = 0, + max_num_inst = 0, + min_num_inst = 0, + tolerance = 0.1, + max_num_level = 2, + coarsening_ratio = 10.0, + large_net_threshold = 50, + signature_net_threshold = 50, + halo_width = 2.0, + halo_height = 2.0, + fence_lx = block.dbuToMicrons(core.xMin()), + fence_ly = block.dbuToMicrons(core.yMin()), + fence_ux = block.dbuToMicrons(core.xMax()), + fence_uy = block.dbuToMicrons(core.yMax()), + area_weight = 0.1, + outline_weight = 100.0, + wirelength_weight = 100.0, + guidance_weight = 10.0, + fence_weight = 10.0, + boundary_weight = 50.0, + notch_weight = 10.0, + macro_blockage_weight = 10.0, + pin_access_th = 0.0, + target_util = 0.25, + target_dead_space = 0.05, + min_ar = 0.33, + snap_layer = 4, + bus_planning_flag = False, + report_directory = """" + )" +Template of running detailed placement,"# Run initial detailed placement +site = design.getBlock().getRows()[0].getSite() +# Allow 1um x-displacement and 3um y-displacement +max_disp_x = int(design.micronToDBU(1)) +max_disp_y = int(design.micronToDBU(3)) +# Remove filler cells to be able to move the cells +design.getOpendp().removeFillers() +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)" +Template of running CTS (clock tree synthesis),"# Configure and run clock tree synthesis +design.evalTclString(""set_propagated_clock [get_clocks {core_clock}]"") +# Set RC values for clock and signal nets +design.evalTclString(""set_wire_rc -clock -resistance 0.03574 -capacitance 0.07516"") +design.evalTclString(""set_wire_rc -signal -resistance 0.03574 -capacitance 0.07516"") +cts = design.getTritonCts() +parms = cts.getParms() +parms.setWireSegmentUnit(20) +# Configure clock buffers +cts.setBufferList(""BUF_X2"") +cts.setRootBuffer(""BUF_X2"") +cts.setSinkBuffer(""BUF_X2"") +cts.runTritonCts() + +# Run final detailed placement +site = design.getBlock().getRows()[0].getSite() +max_disp_x = int(design.micronToDBU(1) / site.getWidth()) +max_disp_y = int(design.micronToDBU(3) / site.getHeight()) +design.getOpendp().detailedPlacement(max_disp_x, max_disp_y, """", False)" +Template of placing filler cells,"import openroad as ord +# Insert filler cells +db = ord.get_db() +filler_masters = list() +# filler cells' naming convention +filler_cells_prefix = ""FILLCELL_"" +for lib in db.getLibs(): + for master in lib.getMasters(): + if master.getType() == ""CORE_SPACER"": + filler_masters.append(master) +if len(filler_masters) == 0: + print(""no filler cells in library!"") +else: + design.getOpendp().fillerPlacement(filler_masters = filler_masters, + prefix = filler_cells_prefix, + verbose = False)" +Template of performing power planning (creating power delivery network (PDN)) with power rings,"import pdn, odb +# Configure power delivery network +# Set up global power/ground connections +for net in design.getBlock().getNets(): + if net.getSigType() == ""POWER"" or net.getSigType() == ""GROUND"": + net.setSpecial() +VDD_net = design.getBlock().findNet(""VDD"") +VSS_net = design.getBlock().findNet(""VSS"") +switched_power = None +secondary = list() +# Create VDD/VSS nets if they don't exist +if VDD_net == None: + VDD_net = odb.dbNet_create(design.getBlock(), ""VDD"") + VDD_net.setSpecial() + VDD_net.setSigType(""POWER"") +if VSS_net == None: + VSS_net = odb.dbNet_create(design.getBlock(), ""VSS"") + VSS_net.setSpecial() + VSS_net.setSigType(""GROUND"") + +# Connect power pins to global nets +design.getBlock().addGlobalConnect(region = None, + instPattern = "".*"", + pinPattern = ""^VDD$"", + net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, + instPattern = "".*"", + pinPattern = ""^VDDPE$"", + net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, + instPattern = "".*"", + pinPattern = ""^VDDCE$"", + net = VDD_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, + instPattern = "".*"", + pinPattern = ""^VSS$"", + net = VSS_net, + do_connect = True) +design.getBlock().addGlobalConnect(region = None, + instPattern = "".*"", + pinPattern = ""^VSSE$"", + net = VSS_net, + do_connect = True) +design.getBlock().globalConnect() + +# Configure power domains +pdngen = design.getPdnGen() +pdngen.setCoreDomain(power = VDD_net, + switched_power = switched_power, + ground = VSS_net, + secondary = secondary) + +# Configure power ring dimensions +core_ring_width = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_spacing = [design.micronToDBU(2), design.micronToDBU(2)] +core_ring_core_offset = [design.micronToDBU(0) for i in range(4)] +core_ring_pad_offset = [design.micronToDBU(0) for i in range(4)] +pdn_cut_pitch = [design.micronToDBU(0) for i in range(2)] + +# Get routing layers for power ring connections +ring_connect_to_pad_layers = list() +for layer in design.getTech().getDB().getTech().getLayers(): + if layer.getType() == ""ROUTING"": + ring_connect_to_pad_layers.append(layer) + +# Create power grid for standard cells +domains = [pdngen.findDomain(""Core"")] +halo = [design.micronToDBU(0) for i in range(4)] +for domain in domains: + pdngen.makeCoreGrid(domain = domain, + name = ""top"", + starts_with = pdn.GROUND, + pin_layers = [], + generate_obstructions = [], + powercell = None, + powercontrol = None, + powercontrolnetwork = ""STAR"") + +# Get metal layers for power grid +m1 = design.getTech().getDB().getTech().findLayer(""metal1"") +m4 = design.getTech().getDB().getTech().findLayer(""metal4"") +m7 = design.getTech().getDB().getTech().findLayer(""metal7"") +m8 = design.getTech().getDB().getTech().findLayer(""metal8"") + +grid = pdngen.findGrid(""top"") +for g in grid: + # Create power rings around core area + pdngen.makeRing(grid = g, + layer0 = m7, + width0 = core_ring_width[0], + spacing0 = core_ring_spacing[0], + layer1 = m8, + width1 = core_ring_width[0], + spacing1 = core_ring_spacing[0], + starts_with = pdn.GRID, + offset = core_ring_core_offset, + pad_offset = core_ring_pad_offset, + extend = False, + pad_pin_layers = ring_connect_to_pad_layers, + nets = [], + allow_out_of_die = True) + + # Create horizontal power straps on metal1 for standard cell connections + pdngen.makeFollowpin(grid = g, + layer = m1, + width = design.micronToDBU(0.07), + extend = pdn.CORE) + + # Create vertical power straps on metal4 and metal7 + pdngen.makeStrap(grid = g, + layer = m4, + width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), + pitch = design.micronToDBU(6), + offset = design.micronToDBU(0), + number_of_straps = 0, + snap = False, + starts_with = pdn.GRID, + extend = pdn.CORE, + nets = []) + pdngen.makeStrap(grid = g, + layer = m7, + width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), + pitch = design.micronToDBU(10.8), + offset = design.micronToDBU(0), + number_of_straps = 0, + snap = False, + starts_with = pdn.GRID, + extend = pdn.RINGS, + nets = []) + pdngen.makeStrap(grid = g, + layer = m8, + width = design.micronToDBU(1.4), + spacing = design.micronToDBU(1.4), + pitch = design.micronToDBU(10.8), + offset = design.micronToDBU(0), + number_of_straps = 0, + snap = False, + starts_with = pdn.GRID, + extend = pdn.BOUNDARY, + nets = []) + + # Create via connections between power grid layers + pdngen.makeConnect(grid = g, + layer0 = m1, + layer1 = m4, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + pdngen.makeConnect(grid = g, + layer0 = m4, + layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + pdngen.makeConnect(grid = g, + layer0 = m7, + layer1 = m8, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + +# Verify and build power grid +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()" +Template of creating power distribute networks (PDN) for macros,"import pdn +pdngen = design.getPdnGen() +domains = [pdngen.findDomain(""Core"")] +# Create power grid for macro blocks +macros = [inst for inst in design.getBlock().getInsts() if inst.getMaster().isBlock()] +m5 = design.getTech().getDB().getTech().findLayer(""metal5"") +m6 = design.getTech().getDB().getTech().findLayer(""metal6"") +for i in range(len(macros)): + # Create power grid for each macro + for domain in domains: + pdngen.makeInstanceGrid(domain = domain, + name = ""CORE_macro_grid_"" + str(i), + starts_with = pdn.GROUND, + inst = macros[i], + halo = halo, + pg_pins_to_boundary = True, + default_grid = False, + generate_obstructions = [], + is_bump = False) + grid = pdngen.findGrid(""CORE_macro_grid_"" + str(i)) + for g in grid: + # Create power straps on metal5 and metal6 for macro connections + pdngen.makeStrap(grid = g, + layer = m5, + width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), + pitch = design.micronToDBU(6), + offset = design.micronToDBU(0), + number_of_straps = 0, + snap = True, + starts_with = pdn.GRID, + extend = pdn.CORE, + nets = []) + pdngen.makeStrap(grid = g, + layer = m6, + width = design.micronToDBU(1.2), + spacing = design.micronToDBU(1.2), + pitch = design.micronToDBU(6), + offset = design.micronToDBU(0), + number_of_straps = 0, + snap = True, + starts_with = pdn.GRID, + extend = pdn.CORE, + nets = []) + + # Create via connections between macro power grid layers + pdngen.makeConnect(grid = g, + layer0 = m4, + layer1 = m5, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + pdngen.makeConnect(grid = g, + layer0 = m5, + layer1 = m6, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + pdngen.makeConnect(grid = g, + layer0 = m6, + layer1 = m7, + cut_pitch_x = pdn_cut_pitch[0], + cut_pitch_y = pdn_cut_pitch[1], + vias = [], + techvias = [], + max_rows = 0, + max_columns = 0, + ongrid = [], + split_cuts = dict(), + dont_use_vias = """") + +# Verify and build power grid +pdngen.checkSetup() +pdngen.buildGrids(False) +pdngen.writeToDb(True, ) +pdngen.resetShapes()" +Template of performing IR (voltage) drop analysis for nodes on metal 1 grids,"import psm + +# Run static IR drop analysis +psm_obj = design.getPDNSim() +timing = Timing(design) +source_types = [psm.GeneratedSourceType_FULL, + psm.GeneratedSourceType_STRAPS, + psm.GeneratedSourceType_BUMPS] +# Analyze VDD power grid IR drop +psm_obj.analyzePowerGrid(net = design.getBlock().findNet(""VDD""), + enable_em = False, corner = timing.getCorners()[0], + use_prev_solution = False, + em_file = """", + error_file = """", + voltage_source_file = """", + voltage_file = """", + source_type = source_types[2])" +"Template of reporting internal power, switching power, and leakage power","# Report Power +design.evalTclString(""report_power"")" +Template of performing global routing,"# Configure and run global routing +# Set routing layer ranges for signal and clock nets +signal_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +signal_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() +clk_low_layer = design.getTech().getDB().getTech().findLayer(""metal1"").getRoutingLevel() +clk_high_layer = design.getTech().getDB().getTech().findLayer(""metal7"").getRoutingLevel() + +grt = design.getGlobalRouter() +grt.setMinRoutingLayer(signal_low_layer) +grt.setMaxRoutingLayer(signal_high_layer) +grt.setMinLayerForClock(clk_low_layer) +grt.setMaxLayerForClock(clk_high_layer) +grt.setAdjustment(0.5) +grt.setVerbose(True) +grt.globalRoute(True)" +Template of performing detailed routing,"import drt + +# Configure and run detailed routing +drter = design.getTritonRoute() +params = drt.ParamStruct() +params.outputMazeFile = """" +params.outputDrcFile = """" +params.outputCmapFile = """" +params.outputGuideCoverageFile = """" +params.dbProcessNode = """" +params.enableViaGen = True +params.drouteEndIter = 1 +params.viaInPinBottomLayer = """" +params.viaInPinTopLayer = """" +params.orSeed = -1 +params.orK = 0 +params.bottomRoutingLayer = ""metal1"" +params.topRoutingLayer = ""metal7"" +params.verbose = 1 +params.cleanPatches = True +params.doPa = True +params.singleStepDR = False +params.minAccessPoints = 1 +params.saveGuideUpdates = False +drter.setParams(params) +drter.main()" +Template function to horizontally flip the instance,"# This function is not provided by OpenROAD, you have to create this function. +def flipX(value): + if value == ""R0"": + return ""MX"" + elif value == ""R90"": + return ""MYR90"" + elif value == ""R180"": + return ""MY"" + elif value == ""R270"": + return ""MXR90"" + elif value == ""MY"": + return ""R180"" + elif value == ""MYR90"": + return ""R90"" + elif value == ""MX"": + return ""R0"" + elif value == ""MXR90"": + return ""R270""" +Template function to vertically flip the instance,"# This function is not provided by OpenROAD, you have to create this function. +def flipY(value): + if value == ""R0"": + return ""MY"" + elif value == ""R90"": + return ""MXR90"" + elif value == ""R180"": + return ""MX"" + elif value == ""R270"": + return ""MYR90"" + elif value == ""MY"": + return ""R0"" + elif value == ""MYR90"": + return ""R270"" + elif value == ""MX"": + return ""R180"" + elif value == ""MXR90"": + return ""R90""" +Template of getting the library cell (master cell) from the OpenROAD db,"# Get the database +db = ord.get_db() +# Define the new library cell name +new_mast_name = 'NOR_2X6' +# Check if the required library cell exists in the database +new_mast = db.findMaster(new_mast_name)" \ No newline at end of file diff --git a/flow-Agent/rag_data/RAGFLOWGUIDE.csv b/flow-Agent/rag_data/RAGFLOWGUIDE.csv new file mode 100644 index 0000000..d498d5b --- /dev/null +++ b/flow-Agent/rag_data/RAGFLOWGUIDE.csv @@ -0,0 +1,4044 @@ +FlowStage,ErrorMessage,LikelyCause,RecommendedFix,ExampleWrongCode +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'exportDef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +TypeError: Design.writeDb() got an unexpected keyword argument 'overwrite'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'executeTclCommand'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) referenced +[WARNING ODB-0176] error: undefined layer (metal3) r",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'saveDef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'saveDb'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'generateVerilog'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'loadLiberty' +. Did you mean: 'readLiberty +'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'initializeLef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +TypeError: Tech.readLiberty() got an unexpected keyword argument 'verbose'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'saveDesignDef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'exportDb'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'runTclString' +. Did you mean: 'evalTclString'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'importLiberty'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'loadLef' +. Did you mean: 'readLef'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'processLef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'writeDefWithOptions'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'storeDatabase'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'exportVerilog'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'addLiberty' +. Did you mean: 'readLiberty'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +TypeError: Tech.readLiberty() got an unexpected keyword argument 'verbose'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'saveDef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'commitDb'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'executeVerilogCommand'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'loadLef' +. Did you mean: 'readLef'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_64x21.lef, created 1 library cells +[INFO ODB-0227] LEF file: ../Design/nangate45/lef/fakeram45_256x32.lef, created 1 library ce",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"[INFO ODB-0227] LEF file: ../Design/nangate45/lef/NangateOpenCellLibrary.tech.lef, created 22 layers, 27 vias + + + +Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Tech' object has no attribute 'loadLef' +. Did you mean: 'readLef'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'storeDef'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'saveDesign'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILE,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'executeVerilogCommand'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'createTrack",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"Traceback (most recent call last): + File """", line 1, in +File ""ifp_py.py"", line 321, in initFloorplan +TypeError: Wrong number or type of arguments for overloaded function 'InitFloorplan_initFloorplan'. + Possible C/C++ prototypes are: + ifp::InitFloorplan::initFloorplan(double,doub",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'generateTra",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"Traceback (most recent call last): + File """", line 1, in +File ""ifp_py.py"", line 321, in initFloorplan +TypeError: Wrong number or type of arguments for overloaded function 'InitFloorplan_initFloorplan'. + Possible C/C++ prototypes are: + ifp::InitFloorplan::initFloorplan(double,doub",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'setupTracks",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"Traceback (most recent call last): + File """", line 1, in +File ""ifp_py.py"", line 321, in initFloorplan +TypeError: Wrong number or type of arguments for overloaded function 'InitFloorplan_initFloorplan'. + Possible C/C++ prototypes are: + ifp::InitFloorplan::initFloorplan(double,doub",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'makeTracksW",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"Traceback (most recent call last): + File """", line 1, in +File ""ifp_py.py"", line 321, in initFloorplan +TypeError: Wrong number or type of arguments for overloaded function 'InitFloorplan_initFloorplan'. + Possible C/C++ prototypes are: + ifp::InitFloorplan::initFloorplan(double,doub",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'defineTrack",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (10.000, 10.000) snapped to (10.070, 11.200). +[INFO IFP-0001] Added 256 rows of 1897 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'estab",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.130, 5.600). +[INFO IFP-0001] Added 28 rows of 262 site FreePDK45_38x28_10R_NP_162NW_34O. + +Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'setupTracks",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FLOORPLAN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'InitFloorplan' object has no attribute 'runFloorplan' +. Did you mean: 'initFloorplan'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'addHorizontalLayer'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'printConfig'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'obtainTopLayer'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Parameters' object has no attribute 'defineMinSpacing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'configureHorizontalLength'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'configureVerticalLength'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'addVerticalLayer' +. Did you mean: 'addVerLayer'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'printConfig'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'fetchIOPlacer' +. Did you mean: 'getIOPlacer'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Parameters' object has no attribute 'configureMinDistance'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'setHorizontalLengthWithMode' +. Did you mean: 'setHorizontalLengthExtend'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'updateVerticalLength' +. Did you mean: 'getVerticalLength'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'executeAnnealing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'printConfig'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'fetchTopLayer' +. Did you mean: 'getTopLayer +'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'setMinDistanceInTracksWithMode' +. Did you mean: 'setMinDistanceInTracks'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +TypeError: Parameters.setHorizontalLength() got an unexpected keyword argument 'mode'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'adjustVerticalLength' +. Did you mean: 'getVerticalLength'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'runAnnealingWithConfig' +. Did you mean: 'setAnnealingConfig'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'printConfig'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'retrieveIOPlacer'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Parameters' object has no attribute 'applyMinDistance' +. Did you mean: 'getMinDistance'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'updateHorizontalLength' +. Did you mean: 'getHorizontalLength'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'applyVerticalLength' +. Did you mean: 'getVerticalLength'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +TypeError: IOPlacer.runAnnealing() takes 2 positional arguments but 3 were given",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'showConfiguration'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'getUpperLayer' +. Did you mean: 'getTopLayer'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Parameters' object has no attribute 'setMinimumSpacing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'setHorizontalLengthExtended' +. Did you mean: 'setHorizontalLengthExtend'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +TypeError: Parameters.setVerticalLength() takes 2 positional arguments but 3 were given",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'startSimulatedAnnealing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'printConfig'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'IOPlacer' object has no attribute 'retrieveTopLayerInfo'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 2, in +TypeError: Parameters.setMinDistance() takes 2 positional arguments but 3 were given",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +TypeError: Parameters.setHorizontalLength() got an unexpected keyword argument 'scale'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IO,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Parameters' object has no attribute 'modifyVerticalLength' +. Did you mean: 'getVerticalLength'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"[INFO GPL-0002] DBU: 2000 +[INFO GPL-0003] SiteSize: ( 0.190 1.400 ) um +[INFO GPL-0004] CoreBBox: ( 10.070 11.200 ) ( 56.430 56.000 ) um +[INFO GPL-0006] NumInstances: 503 +[INFO GPL-0007] NumPlaceInstances: 503 +[INFO GPL-0008] NumFixedInstances: 0 +[INFO GPL-0009] Nu",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"[INFO GPL-0002] DBU: 2000 +[INFO GPL-0003] SiteSize: ( 0.190 1.400 ) um +[INFO GPL-0004] CoreBBox: ( 10.070 11.200 ) ( 56.430 56.000 ) um +[INFO GPL-0006] NumInstances: 503 +[INFO GPL-0007] NumPlaceInstances: 503 +[INFO GPL-0008] NumFixedInstances: 0 +[INFO GPL-0009] Nu",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Replace' object has no attribute 'executeInitialPlacement'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"[INFO GPL-0002] DBU: 2000 +[INFO GPL-0003] SiteSize: ( 0.190 1.400 ) um +[INFO GPL-0004] CoreBBox: ( 10.070 11.200 ) ( 56.430 56.000 ) um +[INFO GPL-0006] NumInstances: 503 +[INFO GPL-0007] NumPlaceInstances: 503 +[INFO GPL-0008] NumFixedInstances: 0 +[INFO GPL-0009] Nu",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Replace' object has no attribute 'setBalancedTargetDensityMode' +. Did you mean: 'setUniformTargetDensityMode'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Replace' object has no attribute 'enableUniformDensitySetting'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 5, in +TypeError: MacroPlacer.placeMacro() got an unexpected keyword argument 'num_threads'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 5, in +TypeError: MacroPlacer.place() missing 1 required positional argument: 'max_num_macro'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Design' object has no attribute 'macroPlacer' +. Did you mean: 'getMacroPlacer'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 5, in +TypeError: MacroPlacer.place() missing 1 required positional argument: 'halo_height'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 5, in +File ""mpl_py.py"", line 238, in place +TypeError: in method 'MacroPlacer_place', argument 30 of type 'int'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +MPL,"Traceback (most recent call last): + File """", line 2, in +AttributeError: 'Design' object has no attribute 'getOpenROADMacroPlacer'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +File ""dpl_py.py"", line 139, in detailedPlacement +TypeError: Opendp_detailedPlacement expected at most 5 arguments, got 6 +Additional information: +Wrong number or type of arguments for overloaded function 'Opendp_detailedPlacemen",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Opendp' object has no attribute 'clearFillers'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'dbRow' object has no attribute 'fetchSite' +. Did you mean: 'getSite'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Opendp' object has no attribute 'clearFillerCells'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Opendp' object has no attribute 'executePlacement' +. Did you mean: 'checkPlacement'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DPL,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Opendp' object has no attribute 'purgeFillers'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"invalid command name ""make_clock""'",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): + +File """", line 1, in + +AttributeError +: +'TritonCTS' object has no attribute 'setBufferListWithType'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"invalid command name ""initialize_clock""'",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'TritonCTS' object has no attribute 'assignBufferList' +. Did you mean: 'setBufferList'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"wrong # args: should be ""define_clock_layer_range layers""'",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): + File """", line 1, in + +File ""dpl_py.py"", line 139, in detailedPlacement + +TypeError +: +Opendp_detailedPlacement expected at most 5 arguments, got 6 +Additional information: +Wrong number or type of arguments for overloaded function 'Opendp_detailedPlace",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"invalid command name ""setup_clock""'",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): +File """", line 1, in + +AttributeError +: +'Opendp' object has no attribute 'advancedDetailedPlacement'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"[ERROR STA-0562] create_clock -target is not a known keyword or flag. +'STA-0562'",OpenROAD执行阶段失败(配置或文件路径问题),检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'TritonCTS' object has no attribute 'configureBufferList'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"invalid command name ""assign_clock""'",未知错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +CTS,"Traceback (most recent call last): + +File """", line 1, in + +AttributeError +: +'TritonCTS' object has no attribute 'setFinalSinkBuffer' +. Did you mean: ' +setSinkBuffer +'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 3, in +AttributeError: 'dbMaster' object has no attribute 'getCellType'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + +Traceback (most recent call last): + File """", line 4, in +AttributeError: 'dbInst' object has no attribute 'remove'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 4, in +TypeError: Opendp.fillerPlacement() got an unexpected keyword argument 'filler_cell_naming_rule'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + +Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Design' object has no attribute 'removeFiller'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 4, in +TypeError: Opendp.fillerPlacement() got an unexpected keyword argument 'filler_cells'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + +Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Design' object has no attribute 'deleteFiller'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Design' object has no attribute 'getOpenROADFillerCellInsert'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + + +Traceback (most recent call last): + File """", line 5, in +AttributeError: 'dbInst' object has no attribute 'destory' +. Did you mean: 'destroy'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Opendp' object has no attribute 'fillerInsert'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + +Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Design' object has no attribute 'getOpenDp' +. Did you mean: 'getOpendp'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Opendp' object has no attribute 'fillerCellPlacement' +. Did you mean: 'fillerPlacement'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +FILLER,"[INFO DPL-0001] Placed 776 filler instances. + + + + + + + +Traceback (most recent call last): + File """", line 4, in +AttributeError: 'Design' object has no attribute 'getOpenDp' +. Did you mean: 'getOpendp'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + +0 + + + + + + +0 + + + + + + +503 + + + + + + +0 + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 2, in +AttributeError: 'PdnGen' object has no attribute 'createRing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 4, in +AttributeError: 'dbNet' object has no attribute 'assignSigType'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """,Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'PdnGen' object has no attribute 'removeGrid'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + +0 + + + + + + +0 + + + + + + +503 + + + + + + +0 + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 46, in +AttributeError: 'PdnGen' object has no attribute 'connectVia'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'createConnect' +. Did you mean: 'm",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'createConnect' +. Did you mean: 'm",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'PdnGen' object has no attribute 'disconnectGrid'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + +0 + + + + + + +0 + + + + + + +503 + + + + + + +0 + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 46, in +AttributeError: 'PdnGen' object has no attribute 'connectVia'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'connectLayers'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 8, in +TypeError: PdnGen.makeStrap() got an unexpected keyword argument 'alignment'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +TypeError: PdnGen.ripUp() got an unexpected keyword argument 'force'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + +0 + + + + + + +0 + + + + + + +503 + + + + + + +0 + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 3, in +AttributeError: 'PdnGen' object has no attribute 'constructRing'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'connectLayers'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 8, in +TypeError: PdnGen.makeStrap() got an unexpected keyword argument 'optimize'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'PdnGen' object has no attribute 'removeGrid'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + +0 + + + + + + +0 + + + + + + +503 + + + + + + +0 + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 18, in +AttributeError: 'PdnGen' object has no attribute 'attachFollowp",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'connectLayers'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'linkConnect' +. Did you mean: 'mak",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'PdnGen' object has no attribute 'destroyGrid'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'dbBlock' object has no attribute 'addPDNConnect'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 74, in +AttributeError: 'PdnGen' object has no attribute",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'establishConnectivity'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"503 + + + + + + + +0 + + + + + + + +0 + + + + + + + +503 + + + + + + + +0 + + + +0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Traceback (most recent call last): + File """", line 33, in +AttributeError: 'PdnGen' object has no attribute 'linkConnect' +. Did you mean: 'mak",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +PDN,"Traceback (most recent call last): + File """", line 1, in +TypeError: PdnGen.ripUp() got an unexpected keyword argument 'mode'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +TypeError: GlobalRouter.setAdjustment() takes 2 positional arguments but 3 were given",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'GlobalRouter' object has no attribute 'executeGlobalRoute'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'GlobalRouter' object has no attribute 'executeGlobalRouting' +. Did you mean: 'boxToGlobalRouting'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'GlobalRouter' object has no attribute 'setRoutingVerbose'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'GlobalRouter' object has no attribute 'enableVerbosity'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +GRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'GlobalRouter' object has no attribute 'enableLogging'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"[ERROR DRT-0002] Detailed routing has not been run yet. +Traceback (most recent call last): + File """", line 1, in +File ""drt_py.py"", line 122, in getNumDRVs +RuntimeError: DRT-0002",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"[ERROR DRT-0002] Detailed routing has not been run yet. +Traceback (most recent call last): + File """", line 1, in +File ""drt_py.py"", line 122, in getNumDRVs +RuntimeError: DRT-0002",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"[ERROR DRT-0002] Detailed routing has not been run yet. +Traceback (most recent call last): + File """", line 1, in +File ""drt_py.py"", line 122, in getNumDRVs +RuntimeError: DRT-0002",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'TritonRoute' object has no attribute 'retrieveNumDRVs'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"[ERROR DRT-0002] Detailed routing has not been run yet. +Traceback (most recent call last): + File """", line 1, in +File ""drt_py.py"", line 122, in getNumDRVs +RuntimeError: DRT-0002",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'drt' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +DRT,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'TritonRoute' object has no attribute 'getDRVCount'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'executeTclCommand'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +TypeError: Design.evalTclString() got an unexpected keyword argument 'detailed'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'executePowerReport'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +TypeError: Design.evalTclString() got an unexpected keyword argument 'level'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +AttributeError: 'Design' object has no attribute 'evalTclScript' +. Did you mean: 'evalTclString'?",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +NameError: name 'psm' is not defined",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, +IR,"Traceback (most recent call last): + File """", line 1, in +TypeError: Design.evalTclString() got an unexpected keyword argument 'mode'",Python语法或API调用错误,检查模块初始化顺序、输入文件路径、API调用参数是否正确。可参考相应的正确脚本示例。, diff --git a/flow-Agent/rag_data/README.md b/flow-Agent/rag_data/README.md new file mode 100644 index 0000000..456a8b8 --- /dev/null +++ b/flow-Agent/rag_data/README.md @@ -0,0 +1 @@ +Stores retrieval databases, design logs, error samples, and knowledge index files. diff --git a/flow-Agent/rag_data/docs.pkl b/flow-Agent/rag_data/docs.pkl new file mode 100644 index 0000000..6a4ac25 Binary files /dev/null and b/flow-Agent/rag_data/docs.pkl differ diff --git a/flow-Agent/rag_data/embeddings.npy b/flow-Agent/rag_data/embeddings.npy new file mode 100644 index 0000000..e070b63 Binary files /dev/null and b/flow-Agent/rag_data/embeddings.npy differ diff --git a/flow-Agent/run_all.sh b/flow-Agent/run_all.sh new file mode 100644 index 0000000..371b613 --- /dev/null +++ b/flow-Agent/run_all.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# run_all.sh - sequentially run maindriver.sh for multiple (design, platform) pairs + +# define (design, platform) pairs +pairs=( + "aes asap7" + "aes sky130hd" + "ibex sky130hd" + "ibex asap7" + "jpeg sky130hd" + "jpeg asap7" +) + +# Execute each combination sequentially +for pair in "${pairs[@]}"; do + read d p <<< "$pair" + echo "===========================================" + echo "Running design: $d, platform: $p" + echo "===========================================" + ./maindriver.sh -p "$p" -d "$d" -o DWL + echo +done diff --git a/flow-Agent/stage_optimize.py b/flow-Agent/stage_optimize.py new file mode 100644 index 0000000..a52efd3 --- /dev/null +++ b/flow-Agent/stage_optimize.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python3 +""" +Stage-level optimization driver for OpenROAD Flow Scripts. + +This tool executes the OpenROAD flow one stage at a time (synth → floorplan → place → cts → route → finish), +collects the resulting metrics/logs, and queries the existing ReAct framework to recommend +stage-local parameter tuning. +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import statistics +import subprocess +import sys +import textwrap +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, Iterable, List, Optional, Tuple + +from optimize import ( + OptimizationWorkflow, + process_log_file, +) + + +@dataclass +class StageDefinition: + """Metadata describing how to run and analyse a single flow stage.""" + + name: str + make_target: str + log_prefix: str + description: str + parameter_keys: List[str] = field(default_factory=list) + + +# Mapping between parameter identifiers used in OptimizationWorkflow and their make/env names. +PARAM_TO_ENV_VAR = { + "synth_flatten": "SYNTH_FLATTEN", + "core_util": "CORE_UTILIZATION", + "cell_pad_global": "CELL_PAD_IN_SITES_GLOBAL_PLACEMENT", + "cell_pad_detail": "CELL_PAD_IN_SITES_DETAIL_PLACEMENT", + "lb_addon": "PLACE_DENSITY_LB_ADDON", + "enable_dpo": "ENABLE_DPO", + "pin_layer": "PIN_LAYER_ADJUST", + "above_layer": "ABOVE_LAYER_ADJUST", + "tns": "TNS_END_PERCENT", + "cts_size": "CTS_CLUSTER_SIZE", + "cts_diameter": "CTS_CLUSTER_DIAMETER", +} + + +def _stage_definitions() -> List[StageDefinition]: + """Return the default stage ordering and configuration.""" + return [ + StageDefinition( + name="synth", + make_target="do-synth", + log_prefix="1_", + description="Logic synthesis using Yosys; focus on timing slack and area metrics.", + parameter_keys=["synth_flatten"], + ), + StageDefinition( + name="floorplan", + make_target="do-floorplan", + log_prefix="2_", + description="Macro and core floorplanning; adjust area utilization and pin placement.", + parameter_keys=[ + "core_util", + "cell_pad_global", + "cell_pad_detail", + "lb_addon", + ], + ), + StageDefinition( + name="place", + make_target="do-place", + log_prefix="3_", + description="Global/detail placement; tune density, legalization and detail placement options.", + parameter_keys=[ + "lb_addon", + "enable_dpo", + "pin_layer", + "above_layer", + ], + ), + StageDefinition( + name="cts", + make_target="do-cts", + log_prefix="4_", + description="Clock-tree synthesis (CTS); control cluster sizing and clock routing targets.", + parameter_keys=[ + "cts_size", + "cts_diameter", + ], + ), + StageDefinition( + name="route", + make_target="do-route", + log_prefix="5_", + description="Global and detailed routing; focus on timing violations and routing congestion.", + parameter_keys=[ + "pin_layer", + "above_layer", + "tns", + ], + ), + StageDefinition( + name="finish", + make_target="do-finish", + log_prefix="6_", + description="Fill, reporting and final sign-off data generation.", + parameter_keys=[], + ), + ] + + +class StageOptimizationDriver: + """Coordinates per-stage execution, log aggregation, and ReAct-based recommendations.""" + + def __init__( + self, + platform: str, + design: str, + objective: str, + stages: Optional[Iterable[str]] = None, + max_react_steps: int = 3, + temperature: float = 0.1, + workdir: Optional[Path] = None, + dry_run: bool = False, + ) -> None: + self.workdir = Path(workdir or os.getcwd()) + self.platform = platform + self.design = design + self.objective = objective.upper() + self.max_react_steps = max_react_steps + self.temperature = temperature + self.dry_run = dry_run + + # Reuse existing workflow components (embeddings, constraints, ReAct client, etc.). + self.workflow = OptimizationWorkflow(platform, design, objective) + self.react = self.workflow.react_framework + self.initial_params = self.workflow.initial_params + self.param_constraints = self.workflow.param_constraints + + # Track per-stage overrides/recommendations. + self.stage_overrides: Dict[str, Dict[str, Any]] = {} + self.stage_recommendations: Dict[str, Dict[str, Any]] = {} + + stage_list = _stage_definitions() + if stages: + stage_filter = {name.lower() for name in stages} + stage_list = [sd for sd in stage_list if sd.name.lower() in stage_filter] + missing = stage_filter.difference({sd.name.lower() for sd in stage_list}) + if missing: + raise ValueError(f"Unknown stages requested: {', '.join(sorted(missing))}") + + self.stage_sequence = stage_list + + # ------------------------------------------------------------------ CLI helpers + def run(self) -> None: + for stage in self.stage_sequence: + self._execute_stage(stage) + + self._print_summary() + + # ------------------------------------------------------------------ Execution + def _execute_stage(self, stage: StageDefinition) -> None: + print(f"\n=== Stage: {stage.name.upper()} ===") + print(stage.description) + + overrides = self.stage_overrides.get(stage.name, {}) + if overrides: + print("Applying overrides:", " ".join(f"{k}={v}" for k, v in overrides.items())) + + command = ["make", stage.make_target] + for env_var, value in overrides.items(): + command.append(f"{env_var}={value}") + + if self.dry_run: + print("(dry-run) Skipping execution:", " ".join(command)) + else: + print("Running:", " ".join(command)) + try: + subprocess.run( + command, + cwd=self.workdir, + check=True, + ) + except subprocess.CalledProcessError as exc: + print(f"[ERROR] Stage '{stage.name}' execution failed with exit code {exc.returncode}") + raise + + stage_data = self._collect_stage_data(stage) + parameter_info = self._get_stage_parameter_info(stage) + + if not parameter_info: + print("No adjustable parameters registered for this stage; skipping ReAct recommendation.") + return + + react_prompt = self._build_stage_prompt(stage, stage_data, parameter_info) + tools = self._build_stage_tools(stage_data, parameter_info) + + print("[INFO] Requesting ReAct recommendations...") + react_result = self.react.run_react_cycle( + initial_prompt=react_prompt, + available_tools=tools, + max_steps=self.max_react_steps, + temperature=self.temperature, + ) + + final_answer = react_result.get("final_answer", "") + recommendations = self._parse_stage_recommendations(stage, final_answer, parameter_info) + if recommendations: + self.stage_recommendations[stage.name] = recommendations + print("[INFO] Recommended adjustments:") + for env_var, value in recommendations.items(): + print(f" - {env_var} := {value}") + else: + print("[WARN] No actionable recommendations parsed from ReAct response.") + + # ------------------------------------------------------------------ Data aggregation + def _collect_stage_data(self, stage: StageDefinition) -> Dict[str, Any]: + log_dir = self.workdir / "logs" + log_files = sorted(log_dir.glob(f"{stage.log_prefix}*.log")) + json_files = sorted(log_dir.glob(f"{stage.log_prefix}*.json")) + + log_summaries = [] + aggregated_metrics: Dict[str, List[float]] = {} + errors: List[str] = [] + + for log_file in log_files: + summary = process_log_file(str(log_file)) + summary["path"] = str(log_file) + log_summaries.append(summary) + + for metric_name, value in summary.get("metrics", {}).items(): + try: + aggregated_metrics.setdefault(metric_name, []).append(float(value)) + except (TypeError, ValueError): + continue + + errors.extend(summary.get("errors", [])) + + aggregated = { + metric: { + "mean": statistics.mean(values) if values else None, + "min": min(values) if values else None, + "max": max(values) if values else None, + "latest": values[-1] if values else None, + "samples": len(values), + } + for metric, values in aggregated_metrics.items() + } + + json_payloads: List[Tuple[str, Any]] = [] + for json_file in json_files: + try: + with open(json_file, "r", encoding="utf-8") as f: + data = json.load(f) + json_payloads.append((str(json_file), data)) + except Exception as exc: # noqa: BLE001 + errors.append(f"Failed to parse {json_file}: {exc}") + + recent_log_snippet = "" + if log_files: + recent_log_snippet = self._tail_file(log_files[-1], max_lines=40) + + return { + "logs": log_summaries, + "metrics": aggregated, + "json": json_payloads, + "errors": errors, + "recent_log_snippet": recent_log_snippet, + } + + def _get_stage_parameter_info(self, stage: StageDefinition) -> List[Dict[str, Any]]: + info: List[Dict[str, Any]] = [] + for param_key in stage.parameter_keys: + env_var = PARAM_TO_ENV_VAR.get(param_key) + constraint = self.param_constraints.get(param_key) + if env_var is None or constraint is None: + continue + + current_value = self._current_env_value(stage.name, env_var, constraint) + info.append( + { + "param_key": param_key, + "env_var": env_var, + "type": constraint.get("type"), + "range": constraint.get("range"), + "current_value": current_value, + } + ) + + return info + + # ------------------------------------------------------------------ Prompt + tools + def _build_stage_prompt( + self, + stage: StageDefinition, + stage_data: Dict[str, Any], + parameter_info: List[Dict[str, Any]], + ) -> str: + metrics_lines = [] + for name, stats in stage_data["metrics"].items(): + metrics_lines.append( + f"- {name}: latest={stats['latest']} mean={stats['mean']} min={stats['min']} max={stats['max']} (samples={stats['samples']})" + ) + metrics_text = "\n".join(metrics_lines) if metrics_lines else "No metrics captured for this stage." + + parameters_text = json.dumps(parameter_info, indent=2) + + errors_text = "\n".join(stage_data.get("errors", [])) or "No errors captured." + log_tail = stage_data.get("recent_log_snippet", "").strip() or "(no log excerpt available)" + + prompt = textwrap.dedent( + f""" + You are assisting with stage-specific optimization of the OpenROAD flow. + + Stage: {stage.name.upper()} + Platform: {self.platform} + Design: {self.design} + Objective: {self.objective} + + Stage description: + {stage.description} + + Recent metrics: + {metrics_text} + + Errors (if any): + {errors_text} + + Recent log excerpt: + ``` + {log_tail} + ``` + + Adjustable parameters for this stage (env vars with ranges and current values): + {parameters_text} + + Requirements: + - Suggest updated values only for the listed parameters. + - Keep all values within the specified ranges and respect their types. + - Focus on improving the stage metrics relevant to the {self.objective} objective. + - Return concise recommendations ready to be passed back to `make` as VAR=value overrides. + + Final Answer format (must be JSON): + Final Answer: {{"parameters": {{"ENV_VAR": value, ...}}, "notes": "short justification"}} + """ + ).strip() + return prompt + + def _build_stage_tools( + self, + stage_data: Dict[str, Any], + parameter_info: List[Dict[str, Any]], + ) -> Dict[str, Any]: + return { + "list_parameters": lambda _: json.dumps(parameter_info, indent=2), + "show_metrics": lambda _: json.dumps(stage_data.get("metrics", {}), indent=2), + "show_errors": lambda _: "\n".join(stage_data.get("errors", [])) or "No errors recorded.", + "show_log_tail": lambda _: stage_data.get("recent_log_snippet", "") or "No log excerpt.", + } + + # ------------------------------------------------------------------ Parsing + helpers + def _parse_stage_recommendations( + self, + stage: StageDefinition, + final_answer: str, + parameter_info: List[Dict[str, Any]], + ) -> Dict[str, Any]: + if not final_answer or "Final Answer" not in final_answer: + return {} + + match = re.search(r"\{.*\}", final_answer, re.DOTALL) + if not match: + return {} + + try: + payload = json.loads(match.group()) + except json.JSONDecodeError: + return {} + + raw_params = payload.get("parameters", payload) + if not isinstance(raw_params, dict): + return {} + + valid_envs = {info["env_var"] for info in parameter_info} + key_to_env = {info["param_key"]: info["env_var"] for info in parameter_info} + recommendations: Dict[str, Any] = {} + + for key, value in raw_params.items(): + env_var = key if key in valid_envs else key_to_env.get(key.lower()) or key_to_env.get(key) + if env_var not in valid_envs: + continue + + constraint = self._constraint_for_env(env_var, parameter_info) + coerced = self._coerce_to_constraint(value, constraint) + if coerced is not None: + recommendations[env_var] = coerced + + return recommendations + + def _constraint_for_env(self, env_var: str, parameter_info: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]: + for info in parameter_info: + if info["env_var"] == env_var: + return { + "type": info.get("type"), + "range": info.get("range"), + } + return None + + def _coerce_to_constraint(self, value: Any, constraint: Optional[Dict[str, Any]]) -> Optional[Any]: + if constraint is None: + return value + + value_type = constraint.get("type") + value_range = constraint.get("range") + + try: + if value_type == "int": + coerced: Any = int(round(float(value))) + elif value_type == "float": + coerced = float(value) + else: + coerced = value + except (TypeError, ValueError): + return None + + if value_range and len(value_range) == 2: + min_val, max_val = value_range + if isinstance(coerced, (int, float)): + coerced = max(min_val, min(max_val, coerced)) + + return coerced + + def _current_env_value(self, stage_name: str, env_var: str, constraint: Dict[str, Any]) -> Any: + if stage_name in self.stage_overrides and env_var in self.stage_overrides[stage_name]: + return self.stage_overrides[stage_name][env_var] + + raw_value = self.initial_params.get(env_var) + if raw_value is None: + raw_value = os.environ.get(env_var) + + if raw_value is None: + return None + + return self._coerce_to_constraint(raw_value, constraint) + + @staticmethod + def _tail_file(path: Path, max_lines: int = 40) -> str: + try: + with open(path, "r", encoding="utf-8", errors="ignore") as f: + lines = f.readlines() + return "".join(lines[-max_lines:]) + except OSError: + return "" + + def _print_summary(self) -> None: + if not self.stage_recommendations: + print("\nNo stage recommendations were produced.") + return + + print("\n=== Stage Recommendations Summary ===") + for stage_name, params in self.stage_recommendations.items(): + print(f"{stage_name.upper()}:") + for env_var, value in params.items(): + print(f" - {env_var} := {value}") + + +def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Run stage-by-stage optimization flow with ReAct recommendations.", + ) + parser.add_argument("platform", help="PDK/platform name (e.g. asap7, sky130hd).") + parser.add_argument("design", help="Design name (e.g. aes, ibex).") + parser.add_argument("objective", help="Optimization objective (ECP, DWL, COMBO).") + parser.add_argument( + "--stages", + nargs="+", + default=None, + help="Subset of stages to run (default: all). Options: synth floorplan place cts route finish.", + ) + parser.add_argument( + "--max-react-steps", + type=int, + default=3, + help="Maximum reasoning steps for the ReAct loop.", + ) + parser.add_argument( + "--temperature", + type=float, + default=0.1, + help="Sampling temperature for the LLM.", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Show the make commands without executing them.", + ) + + return parser.parse_args(argv) + + +def main(argv: Optional[List[str]] = None) -> None: + args = parse_args(argv) + + driver = StageOptimizationDriver( + platform=args.platform, + design=args.design, + objective=args.objective, + stages=args.stages, + max_react_steps=args.max_react_steps, + temperature=args.temperature, + dry_run=args.dry_run, + ) + driver.run() + + +if __name__ == "__main__": + main() + diff --git a/flow-Agent/stage_override.py b/flow-Agent/stage_override.py new file mode 100644 index 0000000..e5a11f2 --- /dev/null +++ b/flow-Agent/stage_override.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python3 +""" +Utility to run stage_optimize.py with explicit per-stage parameter overrides. + +Overrides can be provided via JSON files or inline CLI expressions of the form +`stage.parameter=value`. Parameter tokens may use either the logical parameter +keys (e.g. `core_util`) or their corresponding environment variables +(`CORE_UTILIZATION`). Values are coerced using JSON parsing semantics, so bare +numbers/booleans/null work without quoting while opaque strings can be wrapped +in quotes if needed. +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path +from typing import Any, Dict, Mapping + +from stage_optimize import ( + PARAM_TO_ENV_VAR, + StageOptimizationDriver, + StageDefinition, + _stage_definitions, +) + + +StageOverrideMap = Dict[str, Dict[str, Any]] + + +def _build_stage_lookup() -> Dict[str, StageDefinition]: + return {stage.name.lower(): stage for stage in _stage_definitions()} + + +def _stage_env_vars(stage: StageDefinition) -> Dict[str, None]: + envs: Dict[str, None] = {} + for key in stage.parameter_keys: + env_var = PARAM_TO_ENV_VAR.get(key) + if env_var: + envs[env_var] = None + return envs + + +def _build_env_aliases() -> Dict[str, str]: + aliases: Dict[str, str] = {} + for key, env_var in PARAM_TO_ENV_VAR.items(): + aliases[key.lower()] = env_var + aliases[env_var.lower()] = env_var + return aliases + + +STAGE_LOOKUP = _build_stage_lookup() +ENV_ALIASES = _build_env_aliases() + + +def _resolve_stage(name: str) -> StageDefinition: + lookup_key = name.strip().lower() + if lookup_key not in STAGE_LOOKUP: + raise ValueError(f"Unknown stage '{name}'. Valid stages: {', '.join(sorted(STAGE_LOOKUP))}") + return STAGE_LOOKUP[lookup_key] + + +def _normalize_param(token: str) -> str: + if not token: + raise ValueError("Empty parameter override key encountered.") + alias = ENV_ALIASES.get(token.strip().lower()) + if alias is None: + valid = ", ".join(sorted(set(ENV_ALIASES.values()))) + raise ValueError(f"Unknown parameter '{token}'. Valid options include: {valid}") + return alias + + +def _parse_scalar(raw_value: str) -> Any: + text = raw_value.strip() + if not text: + return "" + try: + return json.loads(text) + except json.JSONDecodeError: + return text + + +def _load_file_overrides(path: Path) -> StageOverrideMap: + if not path.is_file(): + raise ValueError(f"Override file '{path}' does not exist.") + + try: + payload = json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + raise ValueError(f"Failed to parse overrides file '{path}': {exc}") from exc + + if not isinstance(payload, Mapping): + raise ValueError(f"Overrides file '{path}' must contain a JSON object at the top level.") + + return _normalize_stage_mapping(payload, source=str(path)) + + +def _normalize_stage_mapping(data: Mapping[str, Any], *, source: str) -> StageOverrideMap: + overrides: StageOverrideMap = {} + for stage_name, params in data.items(): + stage = _resolve_stage(stage_name) + stage_envs = _stage_env_vars(stage) + if not params: + continue + if not isinstance(params, Mapping): + raise ValueError( + f"{source}: stage '{stage.name}' overrides must be an object of ENV=value entries." + ) + stage_overrides = overrides.setdefault(stage.name, {}) + for param_key, value in params.items(): + env_var = _normalize_param(param_key) + if env_var not in stage_envs: + valid = ", ".join(stage_envs.keys()) or "(no adjustable parameters)" + raise ValueError( + f"{source}: parameter '{env_var}' is not adjustable for stage '{stage.name}'. " + f"Valid parameters: {valid}" + ) + stage_overrides[env_var] = value + return overrides + + +def _parse_inline_overrides(values: Any) -> StageOverrideMap: + overrides: StageOverrideMap = {} + for expr in values or []: + if "=" not in expr: + raise ValueError( + f"Invalid inline override '{expr}'. Expected format 'stage.param=value'." + ) + lhs, rhs = expr.split("=", 1) + if "." not in lhs: + raise ValueError( + f"Invalid inline override '{expr}'. Expected 'stage.param=value' format." + ) + stage_token, param_token = lhs.split(".", 1) + stage = _resolve_stage(stage_token) + env_var = _normalize_param(param_token) + + stage_envs = _stage_env_vars(stage) + if env_var not in stage_envs: + valid = ", ".join(stage_envs.keys()) or "(no adjustable parameters)" + raise ValueError( + f"Inline override '{expr}' targets '{env_var}' which is not adjustable during stage " + f"'{stage.name}'. Valid parameters: {valid}" + ) + + value = _parse_scalar(rhs) + overrides.setdefault(stage.name, {})[env_var] = value + return overrides + + +def _merge_overrides(target: StageOverrideMap, addition: StageOverrideMap) -> None: + for stage, params in addition.items(): + if not params: + continue + target.setdefault(stage, {}).update(params) + + +def run_with_overrides(args: argparse.Namespace) -> None: + overrides: StageOverrideMap = {} + + if args.overrides_file: + for file_path in args.overrides_file: + file_overrides = _load_file_overrides(file_path) + _merge_overrides(overrides, file_overrides) + + inline_overrides = _parse_inline_overrides(args.override) + _merge_overrides(overrides, inline_overrides) + + if not overrides: + raise ValueError("No overrides provided. Use --overrides-file or --override.") + + print("Loaded stage overrides:") + for stage in sorted(overrides): + for env_var, value in overrides[stage].items(): + print(f" {stage}.{env_var} = {value}") + + driver = StageOptimizationDriver( + platform=args.platform, + design=args.design, + objective=args.objective, + stages=args.stages, + max_react_steps=args.max_react_steps, + temperature=args.temperature, + dry_run=args.dry_run, + workdir=args.workdir, + ) + driver.stage_overrides = overrides + driver.run() + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Apply explicit parameter overrides when running stage_optimize.py." + ) + parser.add_argument("platform", help="PDK/platform name (e.g. asap7, sky130hd).") + parser.add_argument("design", help="Design name (e.g. aes, ibex).") + parser.add_argument("objective", help="Optimization objective (ECP, DWL, COMBO).") + parser.add_argument( + "--stages", + nargs="+", + default=None, + help="Subset of stages to run (default: all). Options: synth floorplan place cts route finish.", + ) + parser.add_argument( + "--max-react-steps", + type=int, + default=3, + help="Maximum reasoning steps for the ReAct loop.", + ) + parser.add_argument( + "--temperature", + type=float, + default=0.1, + help="Sampling temperature for the LLM.", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Show the make commands without executing them.", + ) + parser.add_argument( + "--workdir", + type=Path, + default=None, + help="Flow workspace root (default: current working directory).", + ) + parser.add_argument( + "-f", + "--overrides-file", + action="append", + type=Path, + help="Path to a JSON file describing stage overrides.", + ) + parser.add_argument( + "-o", + "--override", + action="append", + default=[], + help="Inline override in the form 'stage.parameter=value'. Repeatable.", + ) + return parser + + +def main(argv: Any = None) -> None: + parser = build_parser() + args = parser.parse_args(argv) + try: + run_with_overrides(args) + except ValueError as exc: + parser.error(str(exc)) + + +if __name__ == "__main__": + main() diff --git a/flow-Agent/test_rag.py b/flow-Agent/test_rag.py new file mode 100644 index 0000000..5914d10 --- /dev/null +++ b/flow-Agent/test_rag.py @@ -0,0 +1,63 @@ +import os +import torch +from sentence_transformers import SentenceTransformer +from rag.index import load_embeddings_and_docs, build_and_save_embeddings +from rag.util import answerWithRAG +from pathlib import Path + +def test_rag(query): + """ + Test the RAG retrieval and response functions. + """ + print("=" * 60) + print("[TEST] Starting RAG Functionality Test") + print("=" * 60) + + # Make sure RAGData exists + if not os.path.exists("rag_date"): + os.makedirs("rag_date", exist_ok=True) + + # Step 1: Build if the embeddings do not exist + emb_path = os.path.join("rag_date", "embeddings.npy") + docs_path = os.path.join("rag_date", "docs.pkl") + + if not os.path.exists(emb_path) or not os.path.exists(docs_path): + print("[INFO] Embeddings not found, building new ones...") + build_and_save_embeddings() + else: + print("[INFO] Embeddings found, skipping build step.") + + # Step 2: Load vector library + print("[INFO] Loading embeddings and documents...") + embeddings_np, docs, docsDict = load_embeddings_and_docs() + embeddings = torch.tensor(embeddings_np) + + # Step 3: Load model + print("[INFO] Loading embedding model...") + model_path = Path(__file__).parent / "models" / "mxbai-embed-large-v1" + + # Key: Switch to the absolute path + model_path = model_path.resolve() + + print("[DEBUG] Using absolute model path:", model_path) + + embeddingModel = SentenceTransformer(str(model_path)) + + # Step 4: Questions and perform the RAG retrieval + print("=" * 60) + print(f"[QUERY] {query}") + print("=" * 60) + answer = answerWithRAG(query, embeddings, embeddingModel, docs, docsDict) + + # Step 5: Output results + print("\n[ANSWER CONTEXT]") + print("-" * 60) + print(answer if answer else "No relevant context found.") + print("-" * 60) + + print("[TEST] RAG test completed successfully.") + + +if __name__ == "__main__": + # You can freely modify the query to test different questions + test_rag("Please analyze the data and provide insights on:1. Key patterns in successful vs unsuccessful runs.2. Parameter ranges that appear promising.3. Any timing or wirelength trends.4. Recommendations for subsequent runs.")